//========================================================================
// SE5 AI Global Functions - Captain Kwok's Balance Mod v125+
//========================================================================
//
// This file contains functions that are used throughout the Balance Mod's scripts
//
// Balance Mod Changes:
// --------------------
// v1.29 Changed - Minor adjustments to repair criteria
//       Added   - New Fx[Get_Planet_Population_Space_Available] to return the amount of population space available
//       Added   - New Fx[Compute_Quadrant_Location] to approximate a player's relative location in the quadrant (center, middle, edge, corner)
// v1.27 Added   - New Fx[Get_Task_Force_Ship_Count] to return the number of ships in a task force
//       Added   - New Fx[Find_Nearest_Destination_In_List] to return the closest destination from a list of possible destinations for a ship
//       Added   - New Fx[Find_Nearest_System_In_List] to return the closest system for a ship from a list of systems
// v1.26 Added   - New Fx[Compute_Number_Of_Techs_Researched] to return the number of tech areas researched by a player
//       Added   - New Fx[Get_Non_Aggression_Status] to return the non-aggression status between two players
// v1.25 Changed - Adjustments to resource balance calculations due to cost structure change
//       Added   - New Fx[Calculate_Planet_Pollution]
//       Added   - New Fx[Determine_Colonization_Settings] to identify restrictions on colonization (normal, only breathable, only home type)
//       Changed - Re-named Fx[Get_Planet_Atmosphere_Type_Name] and Fx[Get_Planet_Physical_Type_Name] to more accurately reflect their function
//       Added   - Fx[Get_Colonization_Ability] and Fx[Get_Colonization_Ability_Name] to understand a player's overall colonization capability
//       Added   - New Fx[Get_Systems_Per_Player] to estimate how many systems per player are available
//       Added   - New Fx[Compute_Player_Overlap] to return how many shared systems two players have
//       Added   - New Fx[Compute_Average_Distance_To_Player] to return average system distance between another player's colonies and an AI's home system
//       Added   - New Fx[Get_Mine_Group_Owner] to return the owner of a mine group
//       Added   - New Fx[Difference_In_Known_Empires] to check if there is a difference in the number of known empires between two empires
//       Added   - New Fx[Get_Task_Force_Role] to return the role name of a ship's task force role
//       Added   - New Fx[Get_Number_Of_Fleets] to return the number of fleets by checking all ships for their fleet IDs (workaround for possible bug around Fleet IDs)
//       Added   - New Fx[Are_Others_Present_In_System] to return if any other player is present in a system
//       Added   - New Fx[List_Package_Items] to output the contents of a log package (trade or gift)
// v1.20 Changed - Updated design type name references
//       Added   - New Fx[Get_Status_Name] to return name of ship status id for debug purposes
//       Added   - New Fx[Add_Tech_Area_To_Research_List]
//       Added   - New Fx[Add_Weapon_To_List]
// v1.19 Added   - New Fx[Do_We_Have_Colonies_In_All_Connected_Systems] to report if a systems is connected to systems with colonies
//       Added   - New Fx[Does_System_Have_No_Planets] to return true if a system has no planets
//       Added   - New Fx[Is_Enemy_Present_In_Adjacent_Systems] to check for enemies in adjacent systems (v1.19a)
//       Added   - New Fx[Get_Native_Atmosphere] to return the AI's native atmosphere (v1.19a)
//       Added   - New Fx[Get_Planet_Physical_Type] to return a string value for a planet's physical type (v1.19a)
//       Added   - New Fx[Get_Long_Abs_Value] to return absolute value of a long (v1.19a)
//       Added   - New Fx[Get_Real_Abs_Value] to return absolute value of a long (v1.19a)
//       Added   - New Fx[Get_Number_Of_Trade_Treaties] to return number of trade treaties an empire has (v1.19a)
//       Added   - New Fx[Estimate_Pending_Resource_Production] to estimate income from new resource facility construction (v1.19c)
//       Added   - New Fx[Compute_Resource_Balance] to update resource modifiers for deficits or surpluses (v1.19c)
//       Added   - New Fx[Compute_Resource_Levels] to update resource modifiers for resource storage levels (v1.19c)
//       Added   - New Fx[Is_Ship_Design_Type_Needed] to determine if we the AI has more of a design type than it currently needs (v1.19c)
//       Added   - New Fx[Is_Component_Damaged] to return if a particularly component on a ship is operable (v1.19f)
//       Added   - New Fx[What_Unit_Type_Is_Our_Main_Cargo] to return a ship's main cargo item (v1.19g)
//       Removed - Fx[Get_Total_Number_Of_Facilities] since it was no longer used (v1.19g)
//       Added   - New Fx[Compute_Resource_Income] to return all resources collected by an empire (v1.19g)
//       Added   - New Fx[Get_Treaty_Friendship_Value] to calculate "friendship value" of a treaty (v1.19h)
//       Added   - New Fx[Find_Nearest_Ship_Distance_To_Location] to return the distance of the closest ship to a specified target (v1.19h)
//       Changed - Revised Fx[Is_Ship_Design_Type_Needed] vehicle design type demand calculation (v1.19h)
//       Removed - Fx[Get_Number_Of_Wars]
//       Added   - New Fx[Do_Ships_In_Fleet_Need_Retrofit] to signal a fleet if a set percentage of its ships need to be retrofit (v1.19h)
//       Added   - New Fx[Get_Mine_Sweep_Count] to return the number of mines a ship could sweep (v1.19i)
//       Added   - New Fx[Get_Mine_Group_Count] to return the number of mines in a sector (v1.19i)
//       Fixed   - Sometimes Fx[Get_Unit_Group_Type] was returning incorrect null values (v1.19i)
//       Added   - New Fx[Does_Another_Ship_Have_Same_Order] to check if a specific ship has the orders we are going to give (v1.19i)
//       Added   - New Fx[Is_Another_Ship_At_Location] to check if a specific ship type is in a location (v1.19i)
//       Added   - New Fx[Get_Design_Name_Suffix_Position] to return the position of a design name suffix (v1.19i)
//       Added   - New Fx[Is_Vehicle_Design_Name_Unique] to check to see if a root design name is used (v1.19i)
//       Added   - New Fx[Get_Unique_Design_Name] to provide an used vehicle design name when required (v1.19i)
//       Added   - New Fx[Find_Nearest_Ship_System_Distance_To_Location] to return the closest specific ship type to a system (v1.19i)
//       Added   - New Fx[Get_Component_Level] to return the level of a component on a ship (v1.19j)
//       Fixed   - Fx[Get_Mine_Group_Count] was not returning the correct number of mines (v1.19j)
//       Added   - New Fx[Can_Facilities_Be_Upgraded] to check if a planet has facilities it can upgrade (v1.19j)
//       Added   - New Fx[Get_Empire_Tech_Level_By_Name] to return the current researched tech level (v1.19j)
//       Added   - New Fx[Is_Design_ID_Ours] to identify if a design id is foreign (v1.19j)
//       Added   - New Fx[Does_Sector_Have_Space_Object_Type] to check a sector for a specific space object type (v1.19j)
// v1.18 Added   - New Fx[Get_Colony_In_Location] to return the planet id of a colony in a specific location
// v1.17 Added   - New Fx[Do_We_Have_Treaty_Element_With_Player] to check for specific elements
//       Added   - New Fx[Find_Alternative_Design_Type_For_Retrofit] to allow cross-retrofits for ships with no new design type upgrade
//       Added   - New Fx[Get_Message_Name] to return the name of a message type for debug purposes
//       Added   - New Fx[Get_Destination_WP_Sector] to return the destination sector of a WP in its destination system
//       Added   - New Fx[Calculate_Sector_Strength] to return the strength of space objects in a specific sector
// v1.16 Fixed   - Fx[Find_Nearest_Colony_System_By_Lightyears] did not consider maximum distance of warp point openers
//       Added   - New Fx[Get_Component_Index]
// v1.15 Changed - Updated design type names used in Fx[Get_General_AI_Design_Type]
//       Added   - New Fx[Get_Government_Type_Id]
//       Added   - New Fx[Get_Society_Type_Id]
//       Added   - New Fx[Does_Enemy_Have_Colony_In_Adjacent_Systems]
//       Added   - New Fx[Do_We_Have_Colonies_In_Adjacent_Systems]
//       Added   - New Fx[Find_Nearest_Colony_System_By_Lightyears]
//       Added   - New Fx[Find_Nearest_System_By_Lightyears]
//       Added   - New Fx[Can_Ship_Repair_Itself]
//       Added   - New Fx[Calculate_Retrofit_Cost_Difference]
//       Added   - New Fx[Calculate_Space_Object_Strength]
//       Fixed   - Error in Fx[Get_Distance_To_Nearest_Colony] was returning the wrong value
//       Changed - Simplified Fx[Is_Planet_Breathable_By_Population]
//       Added   - New Fx[Is_System_Nebula]
//       Added   - New Fx[Is_System_Blackhole]
//       Changed - Fx[Get_Number_Of_Wars] will discount wars against neutral players if already involved in other wars
//       Added   - New Fx[Find_Nearest_Object_In_List] to return the closest object in a list
//       Added   - New Fx[Is_Vehicle_Size_Available] to check for vehicle size in all types
//       Added   - New Fx[At_Max_Ships] to indicate if AI is at maximum number of allowed ships
//       Added   - New Fx[At_Max_units] to indicate if AI is at maximum number of allowed units
//       Added   - New Fx[Is_Player_Enemy] to give more flexibility in the definition of enemy
//       Added   - New Fx[Get_Number_Of_Facility_To_Add] to determine correct number of upgrades to add
//       Added   - New Fx[Get_Number_Of_Facility_Upgrades_In_Progress] to count how specific facility upgrades are in a queue
//       Added   - New Fx[Do_We_Need_More_Cargo] to check if an objects needs to pick up more cargo
//       Added   - New Fx[Get_Order_Name] to convert order numerical constants to in-game string equivalents for debug purposes
//       Added   - New Fx[Convert_Sector_To_String] to convert co-ordinates to in-game string equivalents for debug purposes
//       Added   - New Fx[Get_Treaty_Element_Details] to convert treaty numerical constants to in-game string equivalents for debug purposes
//       Added   - New Fx[Is_System_Protected] to identify if a system is protected from stellar manipulation
//       Added   - New Fx[Get_Planet_Population_Pct] to return a planet's population as a percentage
// v1.14 Added   - New Fx[Get_General_AI_Design_Type] to convert a specific AI design type to a general one
//       Added   - New Fx[Is_Tech_Area_Visible]
//       Added   - New Fx[Get_A_Colony_Location_In_System] to return the sector location of a colony in a specific system
// v1.13 Added   - New Fx[Get_Unit_Group_Type] to return identity of unit groups
//       Added   - New Fx[Is_Enemy_Present_In_Sector]
//       Added   - New Fx[Is_Enemy_Present_In_System]
//       Added   - New Fx[Is_Enemy_Present_At_Destination_WP]
//       Added   - New Fx[Does_Enemy_Have_Colony_In_System]
// v1.12 Changed - Revised Fx[Get_Number_Of_Wars]
//       Added   - New Fx[Get_Planet_Size] to convert planet size to long constant
// v1.10 Changed - Revised Fx[Is_Facility_Present_On_Planet]
//       Added   - New Fx[Is_Facility_Present_In_System]
//       Added   - New Fx[Get_Number_Of_Facilities_On_Planet]
//       Added   - New Fx[Get_Total_Number_Of_Facilities_In_System]
//       Added   - New Fx[Get_Total_Number_Of_Facilities_On_Planet]
//       Added   - New Fx[Is_Tech_Area_Researched]
//       Added   - New Fx[Is_Facility_Queued_On_Planet]
//       Added   - New Fx[Is_Facility_Queued_In_System]
// v1.06 Added   - New Fx[Compute_Resources_Spent]
//       Added   - New Fx[Compute_Resources_Stored]
//       Moved   - Fx[AI_Get_Number_Of_Wars] from Script_AI_GlobalSettings.txt
//       Moved   - Fx[AI_Is_Component_Availble] from Script_AI_GlobalSettings.txt
//       Added   - New Fx[Get_Planet_Atmosphere]
//       Added   - New Fx[Is_Planet_Breathable_By_Population]

// Script Function Requests:
// -------------------------
// - Sys_Get_Maximum_Ships_Allowed : long
// - Sys_Get_Maxium_Units_In_Space_Allowed : long

//------------------------------------------------------------------------
// Get_Long_Abs_Value
//------------------------------------------------------------------------
function Get_Long_Abs_Value returns long
params
  value:                     long
vars
begin

  // Get the parameters absolute value
  if (value < 0) then
    set value := -value
  endif

  return value
end

//------------------------------------------------------------------------
// Get_Real_Abs_Value
//------------------------------------------------------------------------
function Get_Real_Abs_Value returns real
params
  value:                     real
vars
begin

  // Get the parameters absolute value
  if (value < 0) then
    set value := -value
  endif

  return value
end

//------------------------------------------------------------------------
// Get_Median_Value
//------------------------------------------------------------------------
function Get_Median_Value returns long
params
  lst_values:                longlist
vars
  num_values:                long
  mid_index:                 long
  median_value:              long
begin

  set num_values := lst_values.count()

  if (num_values > 0) then
    // Sort the list
    if Sys_Prepare_For_List_Sort() then
      call Sys_Set_List_Sort_Field(1, lst_values)
      call Sys_Add_List_Sort_Sort_Column(1, TRUE)
    endif
    // Determine the middle value
    if Sys_Execute_List_Sort() then
      set mid_index := Sys_Divide_Long(num_values, 2)
      // Even
      if (Sys_Mod_Long(num_values, 2) = 0) then
        set median_value := lst_values.get(mid_index)
      else
        // Odd
        set median_value := Sys_Divide_Long(lst_values.get(mid_index) + lst_values.get(mid_index - 1), 2)
      endif
    endif
  endif

  return median_value
end

//------------------------------------------------------------------------
// At_Max_Ships
//------------------------------------------------------------------------
function At_Max_Ships returns boolean
params
vars
  lst_log_entries:           longlist
  list_count:                long
  list_index:                long
  log_id:                    long
  log_type:                  long
  max_num_ships:             boolean := FALSE
begin

  // Get our current log entries
  call Sys_Empire_Log_Get_Log_Entries_For_This_Turn(sys_long_Player_ID, lst_log_entries)

  // Go through our log entries and look for the maximum ships message
  set list_count := lst_log_entries.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      set log_id := lst_log_entries.get(list_index)
      set log_type := Sys_Empire_Log_Get_Log_Entry_Type(sys_long_Player_ID, log_id)
      // Do we have an entry for max number of ships?
      if (log_type = LOG_TYPE_AT_MAX_SHIPS) then
        set max_num_ships := TRUE
      endif
    endfor
  endif

  return max_num_ships
end

//------------------------------------------------------------------------
// At_Max_Units
//------------------------------------------------------------------------
function At_Max_Units returns boolean
params
vars
  lst_log_entries:           longlist
  list_count:                long
  list_index:                long
  log_id:                    long
  log_type:                  long
  max_num_units:             boolean := FALSE
begin

  // Get our current log entries
  call Sys_Empire_Log_Get_Log_Entries_For_This_Turn(sys_long_Player_ID, lst_log_entries)

  // Go through our log entries and look for the maximum number of units message
  set list_count := lst_log_entries.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      set log_id := lst_log_entries.get(list_index)
      set log_type := Sys_Empire_Log_Get_Log_Entry_Type(sys_long_Player_ID, log_id)
      // Do we have an entry for max number of units?
      if (log_type = LOG_TYPE_AT_MAX_UNITS) then
        set max_num_units := TRUE
      endif
    endfor
  endif

  return max_num_units
end

//------------------------------------------------------------------------
// Convert_Sector_To_String
//------------------------------------------------------------------------
function Convert_Sector_To_String returns string
params
  sect_loc:                  long
vars
  sect_x:                    long
  sect_y:                    long
  sector_name:               string
begin

  // Convert a sector to a string name
  set sect_x := Sys_Mod_Long(sect_loc, 1000) - 100
  set sect_y := Sys_Divide_Long(sect_loc, 1000) - 100
  set sector_name := "(" + Sys_Convert_Long_To_String(sect_x) + ", " + Sys_Convert_Long_To_String(sect_y) + ")"

  return sector_name
end

//------------------------------------------------------------------------
// Get_Design_Suffix_Position
//------------------------------------------------------------------------
function Get_Design_Suffix_Position returns long
params
  design_name:               string
vars
  design_name_length:        long
  design_name_index:         long
  design_name_rev:           string
  design_name_char:          string
  suffix_position:           long
begin

  // Identify the position of the last space in the design name
  set design_name_index := Sys_Length_String(design_name)

  // Process the name from the last character first
  loop
    set design_name_length := Sys_Length_String(design_name)
    set design_name_char := Sys_Delete_String(design_name, 1, design_name_length - 1)
    set design_name := Sys_Delete_String(design_name, design_name_length, 1)
    // If the character is a space, note its position
    if (design_name_char = " ") then
      set suffix_position := design_name_index
    endif
    set design_name_index := design_name_index - 1
    exitwhen (suffix_position > 0) or (design_name_index <= 0)
  endloop

  return suffix_position
end

//------------------------------------------------------------------------
// Is_Vehicle_Design_Name_Unique
//------------------------------------------------------------------------
function Is_Vehicle_Design_Name_Unique returns boolean
params
  check_name:                string
vars
  design_count:              long
  design_index:              long
  design_id:                 long
  design_name:               string
  design_name_length:        long
  design_suffix_pos:         long
  design_suffix:             string
  root_design_name:          string
  design_name_unique:        boolean := TRUE
begin

  // Get our design count
  set design_count := Sys_Get_Player_Designs_Count(sys_long_Player_ID)

  // Check to see if this root design name is already in use
  if (design_count > 0) then
    loop
      set design_index := design_index + 1
      // Get our design's details
      set design_id := Sys_Get_Player_Design_ID(sys_long_Player_ID, design_index)
      set design_name := Sys_Get_Vehicle_Design_Name(design_id)
      set design_name_length := Sys_Length_String(design_name)
      set design_suffix_pos := Get_Design_Suffix_Position(design_name)
      set design_suffix := Sys_Copy_String(design_name, design_suffix_pos, 7)
      // Does the name have a suffix?
      if (lst_AI_Design_Suffixes.indexof(design_suffix) > 0) then
        set root_design_name := Sys_Delete_String(design_name, design_suffix_pos, 7)
      endif
      // Is the root name unique?
      if (root_design_name = check_name) then
        set design_name_unique := FALSE
      endif
      exitwhen (design_index >= design_count) or (not design_name_unique)
    endloop
  endif

  return design_name_unique
end

//------------------------------------------------------------------------
// Get_Unique_Vehicle_Design_Name
//------------------------------------------------------------------------
function Get_Unique_Vehicle_Design_Name returns string
params
vars
  loop_count:                long
  design_name:               string
  design_name_unique:        boolean := FALSE
begin

  // Find a unique design name, avoiding duplicate root names
  loop
    set loop_count := loop_count + 1
    set design_name := Sys_Get_New_Vehicle_Design_Name_Not_In_Use(sys_long_Player_ID)
    set design_name_unique := Is_Vehicle_Design_Name_Unique(design_name)
    // Exit when design name is unique or we've failed to find a unique name
    exitwhen (design_name_unique) or (loop_count >= 10)
  endloop

  // Use any available name, even if it might be contain a duplicate root name
  if (design_name = "") then
    set design_name := Sys_Get_New_Vehicle_Design_Name_Not_In_Use(sys_long_Player_ID)
  endif

  return design_name
end

//------------------------------------------------------------------------
// Get_Message_Type
//------------------------------------------------------------------------
function Get_Message_Type returns string
params
  msg_id:                   long
vars
  msg_type:                 string
begin

  // Return the message name (For debug purposes)
  case msg_id
    POLITICS_MSG_GENERAL_MESSAGE:
      set msg_type := "GENERAL MESSAGE"
    POLITICS_MSG_REPLY_TO_MESSAGE:
      set msg_type := "REPLY TO GENERAL MESSAGE"
    POLITICS_MSG_DECLARE_WAR:
      set msg_type := "DECLARE WAR"
    POLITICS_MSG_SURRENDER:
      set msg_type := "SURRENDER"
    POLITICS_MSG_GRANT_INDEPENDENCE:
      set msg_type := "GRANT INDEPENDENCE"
    POLITICS_MSG_PROPOSE_TREATY:
      set msg_type := "PROPOSE TREATY"
    POLITICS_MSG_PROPOSE_CHANGES_IN_TREATY:
      set msg_type := "PROPOSE CHANGES TO TREATY"
    POLITICS_MSG_ACCEPT_TREATY:
      set msg_type := "ACCEPT TREATY"
    POLITICS_MSG_ACCEPT_TREATY_CHANGES:
      set msg_type := "ACCEPT TREATY CHANGES"
    POLITICS_MSG_REFUSE_TREATY:
      set msg_type := "REFUSE TREATY CHANGES"
    POLITICS_MSG_REFUSE_TREATY_CHANGES:
      set msg_type := "REFUSE TREATY CHANGES"
    POLITICS_MSG_COUNTER_TREATY_PROPOSAL:
      set msg_type := "COUNTER TREATY PROPOSAL"
    POLITICS_MSG_COUNTER_TREATY_CHANGES:
      set msg_type := "COUNTER TREATY CHANGES"
    POLITICS_MSG_BREAK_TREATY:
      set msg_type := "BROKE TREATY"
    POLITICS_MSG_PROPOSE_TRADE:
      set msg_type := "PROPOSE TRADE"
    POLITICS_MSG_ACCEPT_TRADE:
      set msg_type := "ACCEPT TRADE"
    POLITICS_MSG_REFUSE_TRADE:
      set msg_type := "REFUSE TRADE"
    POLITICS_MSG_COUNTER_TRADE:
      set msg_type := "COUNTER TRADE"
    POLITICS_MSG_GIVE_GIFT:
      set msg_type := "GIVE GIFT"
    POLITICS_MSG_ACCEPT_GIFT:
      set msg_type := "ACCEPT GIFT"
    POLITICS_MSG_REFUSE_GIFT:
      set msg_type := "REFUSE GIFT"
    POLITICS_MSG_PROPOSE_NEW_ALLIANCE:
      set msg_type := "PROPOSE NEW ALLIANCE"
    POLITICS_MSG_ACCEPT_ALLIANCE:
      set msg_type := "ACCEPT ALLIANCE"
    POLITICS_MSG_REFUSE_ALLIANCE:
      set msg_type := "REFUSE ALLIANCE"
    POLITICS_MSG_COUNTER_ALLIANCE_PROPOSAL:
      set msg_type := "COUNTER ALLIANCE PROPOSAL"
    POLITICS_MSG_BREAK_WITH_ALLIANCE:
      set msg_type := "BREAK WITH ALLIANCE"
    POLITICS_MSG_CHANGE_ALLIANCE_RULE:
      set msg_type := "CHANGE ALLIANCE RULE"
    POLITICS_MSG_ADD_EMPIRE_TO_ALLIANCE:
      set msg_type := "ADD EMPIRE TO ALLIANCE"
    POLITICS_MSG_REMOVE_EMPIRE_FROM_ALLIANCE:
      set msg_type := "REMOVE EMPIRE FROM ALLIANCE"
    POLITICS_MSG_PROPOSE_EMPIRE_JOIN_ALLIANCE:
      set msg_type := "PROPOSE EMPIRE JOIN ALLIANCE"
    POLITICS_MSG_REQUEST_ACCEPT:
      set msg_type := "ACCEPT REQUEST"
    POLITICS_MSG_REQUEST_REFUSE:
      set msg_type := "REFUSE REQUEST"
    POLITICS_MSG_REQUEST_GIFT:
      set msg_type := "REQUEST GIFT"
    POLITICS_MSG_REQUEST_SURRENDER:
      set msg_type := "REQUEST SURRENDER"
    POLITICS_MSG_REQUEST_STOP_AGGRESSION_AGAINST_EMPIRE:
      set msg_type := "STOP AGGRESSION AGAINST EMPIRE"
    POLITICS_MSG_REQUEST_BREAK_TREATY_WITH_EMPIRE:
      set msg_type := "BREAK TREATY WITH EMPIRE"
    POLITICS_MSG_REQUEST_DECLARE_WAR_ON_EMPIRE:
      set msg_type := "DECLARE WAR ON EMPIRE"
    POLITICS_MSG_REQUEST_MAKE_PEACE_WITH_EMPIRE:
      set msg_type := "MAKE PEACE WITH EMPIRE"
    POLITICS_MSG_REQUEST_TO_JOIN_ALLIANCE:
      set msg_type := "REQUEST TO JOIN ALLIANCE"
    POLITICS_MSG_REQUEST_EMPIRE_BREAK_WITH_ALLIANCE:
      set msg_type := "REQUEST EMPIRE BREAK WITH ALLIANCE"
    POLITICS_MSG_REQUEST_EMPIRE_JOIN_WITH_ALLIANCE:
      set msg_type := "REQUEST EMPIRE JOIN WITH ALLIANCE"
    POLITICS_MSG_REQUEST_STOP_ESPIONAGE_AGAINST_US:
      set msg_type := "REQUEST STOP ESPIONAGE AGAINST US"
    POLITICS_MSG_REQUEST_STOP_ESPIONAGE_AGAINST_EMPIRE:
      set msg_type := "REQUEST STOP ESPIONAGE AGAINST EMPIRE"
    POLITICS_MSG_REQUEST_STOP_SABOTAGE_AGAINST_US:
      set msg_type := "REQUEST STOP SABOTAGE AGAINST US"
    POLITICS_MSG_REQUEST_STOP_SABOTAGE_AGAINST_EMPIRE:
      set msg_type := "REQUEST STOP SABOTAGE AGAINST EMPIRE"
    POLITICS_MSG_REQUEST_STOP_SHIP_ATTACKS_IN_SYSTEM:
      set msg_type := "REQUEST STOP SHIP ATTACKS IN SYSTEM"
    POLITICS_MSG_REQUEST_MILITARY_ASSISTANCE:
      set msg_type := "REQUEST MILITARY ASSISTANCE"
    POLITICS_MSG_REQUEST_MILITARY_ASSISTANCE_AGAINST_EMPIRE:
      set msg_type := "REQUEST MILITARY ASSISTANCE AGAINST EMPIRE"
    POLITICS_MSG_REQUEST_MILITARY_ASSISTANCE_IN_SYSTEM:
      set msg_type := "REQUEST MILITARY ASSISTANCE IN SYSTEM"
    POLITICS_MSG_REQUEST_ECONOMIC_ASSISTANCE:
      set msg_type := "REQUEST ECONOMIC ASSISTANCE"
    POLITICS_MSG_REQUEST_TECHNOLOGICAL_ASSISTANCE:
      set msg_type := "REQUEST TECHNOLOGICAL ASSISTANCE"
    POLITICS_MSG_REQUEST_INTELLIGENCE_ASSISTANCE:
      set msg_type := "REQUEST INTELLIGENCE ASSISTANCE"
    POLITICS_MSG_REQUEST_INTELLIGENCE_ASSISTANCE_AGAINST_EMPIRE:
      set msg_type := "REQUEST INTELLIGENCE ASSISTANCE AGAINST EMPIRE"
    POLITICS_MSG_REQUEST_STOP_BORDER_INCURSIONS:
      set msg_type := "REQUEST STOP BORDER INCURSIONS"
    POLITICS_MSG_REQUEST_STOP_MILITARY_ATTACKS_ON_US:
      set msg_type := "REQUEST STOP MILITARY ATTACKS ON US"
    POLITICS_MSG_REQUEST_STOP_MILITARY_ATTACKS_AGAINST_EMPIRE:
      set msg_type := "REQUEST STOP MILITARY ATTACKS AGAINST EMPIRE"
    POLITICS_MSG_REQUEST_REMOVE_SHIPS_FROM_SYSTEM:
      set msg_type := "REQUEST REMOVE SHIPS FROM SYSTEM"
    POLITICS_MSG_REQUEST_REMOVE_COLONIES_FROM_SYSTEM:
      set msg_type := "REQUEST REMOVE COLONIES FROM SYSTEM"
  endcase

  return msg_type
end

//------------------------------------------------------------------------
// List_Package_Items
//------------------------------------------------------------------------
function List_Package_Items returns boolean
params
  log_id:                    long
  package_type:              long
vars
  list_count:                long
  list_index:                long
  lst_item_type:             longlist
  lst_item_id :              longlist
  lst_item_amount:           longlist
  item_type:                 long
  item_id:                   long
  item_amount:               long
begin

  // What's in the package?
  call Sys_Empire_Log_Get_Package_Items(sys_long_Player_ID, log_id, package_type, lst_item_type, lst_item_id, lst_item_amount)

  set list_count := lst_item_type.count()

  // Go through the package and list the items for debug purposes
  if (list_count > 0) then
    for list_index := 1 to list_count do
      set item_type := lst_item_type.get(list_index)
      set item_id := lst_item_id.get(list_index)
      set item_amount := lst_item_amount.get(list_index)
      // Pending
      case item_type
        MESSAGE_PACKAGE_ITEM_TYPE_SYSTEM:
          // Debug output
          call Sys_Debug_Print("Politics", "    - System = " + Sys_Get_Solar_System_Name(item_id))
        MESSAGE_PACKAGE_ITEM_TYPE_PLANET:
          // Debug output
          call Sys_Debug_Print("Politics", "    - System = " + Sys_Get_Space_Object_Name(item_id))
        MESSAGE_PACKAGE_ITEM_TYPE_RESOURCE:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Resource = " + Sys_Convert_Long_To_String(item_id))
          call Sys_Debug_Print("Politics", "      - Amount = " + Sys_Convert_Long_To_String(item_amount))
        MESSAGE_PACKAGE_ITEM_TYPE_TECHNOLOGY:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Technology = ")
        MESSAGE_PACKAGE_ITEM_TYPE_SHIP:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Ship = " + Sys_Get_Space_Object_Name(item_id))
        MESSAGE_PACKAGE_ITEM_TYPE_STARCHART:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Starchart = " + Sys_Get_Solar_System_Name(item_id))
        MESSAGE_PACKAGE_ITEM_TYPE_COMM:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Comm = " + Sys_Empire_Get_Empire_Name(item_id))
        MESSAGE_PACKAGE_ITEM_TYPE_ANY_PLANET:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Any Planet")
        MESSAGE_PACKAGE_ITEM_TYPE_ANY_TECHNOLOGY:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Any Technology")
        MESSAGE_PACKAGE_ITEM_TYPE_ANY_SHIP:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Any Ship")
        MESSAGE_PACKAGE_ITEM_TYPE_ANY_STARCHART:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Any Starchart")
        MESSAGE_PACKAGE_ITEM_TYPE_ANY_COMM:
          // Debug output
          call Sys_Debug_Print("Politics", "    - Any Comm") 
      endcase
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Get_Memory_Type_Name
//------------------------------------------------------------------------
function Get_Memory_Type_Name returns string
params
  memory_type:               long
vars
  memory_type_name:          string
begin

  case memory_type
    1:
      set memory_type_name := "Log Event"
    2:
      set memory_type_name := "Message Received"
    3:
      set memory_type_name := "Political Status"
    4:
      set memory_type_name := "Political Status with Others"
    5:
      set memory_type_name := "Ships in Territory"
  endcase

  return memory_type_name
end

//------------------------------------------------------------------------
// Get_Memory_Entry_Value_Name
//------------------------------------------------------------------------
function Get_Memory_Entry_Value_Name returns string
params
  memory_entry_type:         long
  memory_entry_type_value:   long
vars
  memory_entry_value_name:   string := "N/A"
begin

  // Log Events
  if (memory_entry_type = MEMORY_ITEM_TYPE_LOG_EVENT) then
    case memory_entry_type_value
      LOG_TYPE_SPACE_COMBAT_DEFENSE_LOST:
        set memory_entry_value_name := "Space Combat Defense Lost"
      LOG_TYPE_SPACE_COMBAT_DEFENSE_WON:
        set memory_entry_value_name := "Space Combat Defense Won"
      LOG_TYPE_SPACE_COMBAT_OFFENSE_LOST:
        set memory_entry_value_name := "Space Combat Offense Lost"
      LOG_TYPE_SPACE_COMBAT_OFFENSE_WON:
        set memory_entry_value_name := "Space Combat Offense Won"
      LOG_TYPE_SPACE_COMBAT_STALEMATE:
        set memory_entry_value_name := "Space Combat Stalemate"
      LOG_TYPE_GROUND_COMBAT_DEFENSE_LOST:
        set memory_entry_value_name := "Ground Combat Defense Lost"
      LOG_TYPE_GROUND_COMBAT_DEFENSE_WON:
        set memory_entry_value_name := "Ground Combat Defense Won"
      LOG_TYPE_GROUND_COMBAT_OFFENSE_LOST:
        set memory_entry_value_name := "Ground Combat Offense Lost"
      LOG_TYPE_GROUND_COMBAT_OFFENSE_WON:
        set memory_entry_value_name := "Ground Combat Offense Won"
      LOG_TYPE_GROUND_COMBAT_STALEMATE:
        set memory_entry_value_name := "Ground Combat Stalemate"
      LOG_TYPE_MINE_EXPLOSION:
        set memory_entry_value_name := "Mine Explosion"
      LOG_TYPE_SABOTAGE_AGAINST_US:
        set memory_entry_value_name := "Sabotage against us"
      LOG_TYPE_ESPIONAGE_AGAINST_US:
        set memory_entry_value_name := "Espionage against us"
      LOG_TYPE_STELLAR_BLACK_HOLE_CREATED:
        set memory_entry_value_name := "Black Hole Created"
      LOG_TYPE_STELLAR_NEBULAE_CREATED:
        set memory_entry_value_name := "Nebula Created"
      LOG_TYPE_STELLAR_PLANET_DESTROYED:
        set memory_entry_value_name := "Planet Destroyed"
      LOG_TYPE_STELLAR_STORM_CREATED:
        set memory_entry_value_name := "Storm Created"
      LOG_TYPE_STELLAR_STAR_DESTROYED:
        set memory_entry_value_name := "Star Destroyed"
      LOG_TYPE_STELLAR_WP_CLOSED:
        set memory_entry_value_name := "Warp Point Closed"
      LOG_TYPE_STELLAR_WP_OPENED:
        set memory_entry_value_name := "Warp Point Opened"
    endcase
  endif

  // Log Messages
  if (memory_entry_type = MEMORY_ITEM_TYPE_MESSAGE_RECEIVED) then
    set memory_entry_value_name := Get_Message_Type(memory_entry_type_value)
  endif

  return memory_entry_value_name
end

//------------------------------------------------------------------------
// Get_Order_Name
//------------------------------------------------------------------------
function Get_Order_Name returns string
params
  order_id:                  long
vars
  order_name:                string
begin

  // Return the corresponding order name (For debug purposes)
  case order_id
    ORDER_MOVETO:
      set order_name := "MOVE TO"
    ORDER_MOVETO_WAYPOINT:
      set order_name := "MOVE TO WAYPOINT"
    ORDER_WARP:
      set order_name := "WARP"
    ORDER_COLONIZE:
      set order_name := "COLONIZE"
    ORDER_EXPLORE:
      set order_name := "EXPLORE"
    ORDER_LOAD:
      set order_name := "LOAD CARGO"
    ORDER_DROP:
      set order_name := "DROP CARGO"
    ORDER_ATTACK_MOVE:
      set order_name := "ATTACK MOVE"
    ORDER_SCRAP:
      set order_name := "SCRAP"
    ORDER_SEEK_LOCATION_INDEF:
      set order_name := "ATTACK SEEK"
    ORDER_SWEEP_MINES:
      set order_name := "SWEEP MINES"
    ORDER_RENDER_MEDICAL_AID:
      set order_name := "CURE PLAGUE"
    ORDER_OPEN_WP:
      set order_name := "OPEN WARP POINT"
    ORDER_CLOSE_WP:
      set order_name := "CLOSE WARP POINT"
    ORDER_CREATE_STORM:
      set order_name := "CREATE STORM"
    ORDER_DESTROY_STORM:
      set order_name := "DESTROY STORM"
    ORDER_CREATE_PLANET:
      set order_name := "CREATE PLANET"
    ORDER_DESTROY_PLANET:
      set order_name := "DESTROY PLANET"
    ORDER_CREATE_SUN:
      set order_name := "CREATE STAR"
    ORDER_DESTROY_SUN:
      set order_name := "DESTROY STAR"
    ORDER_SENTRY:
      set order_name := "SENTRY"
    ORDER_FLEET_TRANSFER:
      set order_name := "FLEET TRANSFER"
    ORDER_REMOVE_FROM_FLEET:
      set order_name := "LEAVE FLEET"
    ORDER_RESUPPLY:
      set order_name := "RESUPPLY"
    ORDER_REPAIR:
      set order_name := "REPAIR"
    ORDER_CLEAR_ORDERS:
      set order_name := "CLEAR ORDERS"
    ORDER_BUILD_QUEUE:
      set order_name := "BUILDING"
    ORDER_TRANSFER_CARGO:
      set order_name := "TRANSFER CARGO"
    ORDER_TRANSFER_UNITS:
      set order_name := "TRANSFER UNITS"
    ORDER_LAUNCH_UNITS:
      set order_name := "LAUNCH UNITS"
    ORDER_RECOVER_UNITS:
      set order_name := "RECOVER UNITS"
    ORDER_CHANGE_ORDERS:
      set order_name := "CHANGE ORDERS"
    ORDER_CHANGE_NAME:
      set order_name := "CHANGE NAME"
    ORDER_PATROL:
      set order_name := "PATROL"
    ORDER_REPEAT_ORDERS:
      set order_name := "REPEAT ORDERS"
    ORDER_ANALYZE:
      set order_name := "ANALYZE"
    ORDER_MOTHBALL:
      set order_name := "MOTHBALL"
    ORDER_UNMOTHBALL:
      set order_name := "UNMOTHBALL"
    ORDER_SELF_DESTRUCT:
      set order_name := "SELF DESTRUCT"
    ORDER_FIRE_ON_SELF:
      set order_name := "FIRE ON SELF"
    ORDER_JOIN_FLEET:
      set order_name := "JOIN FLEET"
    ORDER_JETTISON_CARGO:
      set order_name := "JETTISON CARGO"
    ORDER_SCRAP_CARGO:
      set order_name := "SCRAP CARGO"
    ORDER_CLOAK:
      set order_name := "ORDER CLOAK"
    ORDER_DECLOAK:
      set order_name := "ORDER DECLOAK"
    ORDER_RETROFIT:
      set order_name := "ORDER RETROFIT"
    ORDER_CREATE_NEBULAE:
      set order_name := "CREATE NEBULA"
    ORDER_DESTROY_NEBULAE:
      set order_name := "DESTROY NEBULA"
    ORDER_CREATE_BLACK_HOLE:
      set order_name := "CREATE BLACKHOLE"
    ORDER_DESTROY_BLACK_HOLE:
      set order_name := "DESTROY BLACKHOLE"
    ORDER_CONVERT_RESOURCES:
      set order_name := "CONVERT RESOURCES"
    ORDER_CONSTRUCT_PLANET:
      set order_name := "CONSTRUCT PLANET"
    ORDER_LOAD_SPECIFIC:
      set order_name := "LOAD SPECIFIC CARGO"
    ORDER_DROP_SPECIFIC:
      set order_name := "DROP SPECIFIC CARGO"
    ORDER_LAUNCH_SPECIFIC_UNITS:
      set order_name := "LAUNCH SPECIFIC UNITS"
    ORDER_RECOVER_SPECIFIC_UNITS:
      set order_name := "RECOVER SPECIFIC UNITS"
    ORDER_SURVEY_SYSTEM:
      set order_name := "SURVEY"
    ORDER_MOVE_NEAR:
      set order_name := "MOVE NEAR"
  endcase

  return order_name
end

//------------------------------------------------------------------------
// Get_Status_Name
//------------------------------------------------------------------------
function Get_Status_Name returns string
params
  status_id:                  long
vars
  status_name:                string
begin

  // Return the corresponding order name (For debug purposes)
  case status_id
    SHIP_STATUS_ATTACK:
      set status_name := "ATTACK/DEFEND"
    SHIP_STATUS_PATROL:
      set status_name := "PATROL"
    SHIP_STATUS_ESCORT:
      set status_name := "ESCORT"
    SHIP_STATUS_EXPLORE:
      set status_name := "EXPLORE"
    SHIP_STATUS_SURVEY:
      set status_name := "SURVEY"
    SHIP_STATUS_RESUPPLY:
      set status_name := "RESUPPLY"
    SHIP_STATUS_LOAD_CARGO:
      set status_name := "LOAD CARGO"
    SHIP_STATUS_DROP_CARGO:
      set status_name := "DROP CARGO"
    SHIP_STATUS_LAUNCH:
      set status_name := "LAUNCH CARGO"
    SHIP_STATUS_REMOTE_MINE:
      set status_name := "REMOTE MINE"
    SHIP_STATUS_RETROFIT:
      set status_name := "RETROFIT"
    SHIP_STATUS_SCRAP:
      set status_name := "SCRAP"
    SHIP_STATUS_ANALYZE:
      set status_name := "ANALYZE"
    SHIP_STATUS_FLEET:
      set status_name := "FLEET"
    SHIP_STATUS_REQUEST:
      set status_name := "REQUEST"
  endcase

  return status_name
end

//------------------------------------------------------------------------
// Get_Treaty_Element_Type_Details
//------------------------------------------------------------------------
function Get_Treaty_Element_Type_Details returns string
params
  elem_type:                 long
  elem_value:                long
  entity_id_A:               long
  entity_id_B:               long
vars
  elem_type_details:         string
  entity_name_A:             string
  entity_name_B:             string
begin

  set entity_name_A := Sys_Empire_Get_Empire_Name(entity_id_A)
  set entity_name_B := Sys_Empire_Get_Empire_Name(entity_id_B)

  // Get the corresponding treaty element (For debug purposes)
  case elem_type
    TREATY_ELEMENT_TYPE_TRADE_PERCENT:
      case elem_value
        1:
          set elem_type_details := "Trade (1%)"
        2:
          set elem_type_details := "Trade (2%)"
        3:
          set elem_type_details := "Trade (3%)"
        4:
          set elem_type_details := "Trade (4%)"
        5:
          set elem_type_details := "Trade (5%)"
        6:
          set elem_type_details := "Trade (6%)"
      endcase
    TREATY_ELEMENT_TYPE_NON_AGGRESSION:
      case elem_value
        1:
          set elem_type_details := "Non-Aggression in Colony Systems"
        2:
          set elem_type_details := "Non-Aggression in Neutral Systems"
        3:
          set elem_type_details := "Non-Aggression Allow Colonization"
      endcase
    TREATY_ELEMENT_TYPE_MUTUAL_DEFENSE_PACT:
      set elem_type_details := "Mutual Defense Pact"
    TREATY_ELEMENT_TYPE_ALLOW_MIGRATION_BETWEEN_COLONIES:
      case elem_value
        1:
          set elem_type_details := "Allow Migration %A to %B"
        2:
          set elem_type_details := "Allow Migration %B to %A"
        3:
          set elem_type_details := "Allow Migration Both"
      endcase
    TREATY_ELEMENT_TYPE_TREATIES_WITH_OTHERS:
      case elem_value
        1:
          set elem_type_details := "No Treaties %A"
        2:
          set elem_type_details := "No Treaties/Alliances %A"
        3:
          set elem_type_details := "No Treaties %B"
        4:
          set elem_type_details := "No Treaties/Alliances %B"
        5:
          set elem_type_details := "No Treaties Both"
        6:
          set elem_type_details := "No Treaties/Alliances Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_RESUPPLY:
      case elem_value
        1:
          set elem_type_details := "Share Resupply %A to %B"
        2:
          set elem_type_details := "Share Resupply %B to %A"
        3:
          set elem_type_details := "Share Resupply Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_REPAIR:
      case elem_value
        1:
          set elem_type_details := "Share Repair %A to %B"
        2:
          set elem_type_details := "Share Repair %B to %A"
        3:
          set elem_type_details := "Share Repair Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_TECHNOLOGY:
      case elem_value
        1:
          set elem_type_details := "Share Technology (4 levels old) %A to %B"
        2:
          set elem_type_details := "Share Technology (2 levels old) %A to %B"
        3:
          set elem_type_details := "Share Technology (Current) %A to %B"
        4:
          set elem_type_details := "Share Technology (All) %A to %B"
        5:
          set elem_type_details := "Share Technology (4 levels old) %B to %A"
        6:
          set elem_type_details := "Share Technology (2 levels old) %B to %A"
        7:
          set elem_type_details := "Share Technology (Current) %B to %A"
        8:
          set elem_type_details := "Share Technology (All) %B to %A"
        9:
          set elem_type_details := "Share Technology (4 levels old) Both"
       10:
          set elem_type_details := "Share Technology (2 levels old) Both"
       11:
          set elem_type_details := "Share Technology (Current) Both"
       12:
          set elem_type_details := "Share Technology (All) Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_SYSTEM_MAPS:
      case elem_value
        1:
          set elem_type_details := "Share Maps %A to %B"
        2:
          set elem_type_details := "Share Maps %B to %A"
        3:
          set elem_type_details := "Share Maps Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_COMMUNICATION_CHANNELS:
      case elem_value
        1:
          set elem_type_details := "Share Comm Channels %A to %B"
        2:
          set elem_type_details := "Share Comm Channels %B to %A"
        3:
          set elem_type_details := "Share Comm Channels Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_ESPIONAGE_INFO:
      case elem_value
        1:
          set elem_type_details := "Share Espionage %A to %B"
        2:
          set elem_type_details := "Share Espionage %B to %A"
        3:
          set elem_type_details := "Share Espionage Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_SENSOR_INFO:
      case elem_value
        1:
          set elem_type_details := "Share Sensor Info %A to %B"
        2:
          set elem_type_details := "Share Sensor Info (All) %A to %B"
        3:
          set elem_type_details := "Share Sensor Info %B to %A"
        4:
          set elem_type_details := "Share Sensor Info (All) %B to %A"
        5:
          set elem_type_details := "Share Sensor Info Both"
        6:
          set elem_type_details := "Share Sensor Info (All) Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_DESIGNS:
      case elem_value
        1:
          set elem_type_details := "Share Designs (Enemy) %A to %B"
        2:
          set elem_type_details := "Share Designs (All) %A to %B"
        3:
          set elem_type_details := "Share Designs (Enemy) %B to %A"
        4:
          set elem_type_details := "Share Designs (All) %B to %A"
        5:
          set elem_type_details := "Share Designs (Enemy) Both"
        6:
          set elem_type_details := "Share Designs (All) Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_CODES_FOR_MINEFIELDS:
      case elem_value
        1:
          set elem_type_details := "Share Minefield Codes %A to %B"
        2:
          set elem_type_details := "Share Minefield Codes %B to %A"
        3:
          set elem_type_details := "Share Minefield Codes Both"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_COMBAT_REPORTS:
      case elem_value
        1:
          set elem_type_details := "Share Combat Reports %A to %B"
        2:
          set elem_type_details := "Share Combat Reports %B to %A"
        3:
          set elem_type_details := "Share Combat Reports Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_RESEARCH:
      case elem_value
        1:
          set elem_type_details := "No Research %A"
        2:
          set elem_type_details := "No Research %B"
        3:
          set elem_type_details := "No Research Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_INTELLIGENCE:
      case elem_value
        1:
          set elem_type_details := "No Intelligence %A"
        2:
          set elem_type_details := "No Intelligence %B"
        3:
          set elem_type_details := "No Intelligence Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_BOMBARD_PLANETS:
      case elem_value
        1:
          set elem_type_details := "No Bombardment %A"
        2:
          set elem_type_details := "No Bombardment %B"
        3:
          set elem_type_details := "No Bombardment Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_USE_VIRAL_WEAPONS:
      case elem_value
        1:
          set elem_type_details := "No Viral Weapons %A"
        2:
          set elem_type_details := "No Viral Weapons %B"
        3:
          set elem_type_details := "No Viral Weapons Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_DESTROY_PLANETS:
      case elem_value
        1:
          set elem_type_details := "No Planet Destroying %A"
        2:
          set elem_type_details := "No Planet Destroying %B"
        3:
          set elem_type_details := "No Planet Destroying Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_DESTROY_STARS:
      case elem_value
        1:
          set elem_type_details := "No Star Destroying %A"
        2:
          set elem_type_details := "No Star Destroying %B"
        3:
          set elem_type_details := "No Star Destroying Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_CREATE_BLACKHOLES:
      case elem_value
        1:
          set elem_type_details := "No Blackhole Creation %A"
        2:
          set elem_type_details := "No Blackhole Creation %B"
        3:
          set elem_type_details := "No Blackhole Creation Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_CREATE_NEBULAE:
      case elem_value
        1:
          set elem_type_details := "No Nebulae Creation %A"
        2:
          set elem_type_details := "No Nebulae Creation %B"
        3:
          set elem_type_details := "No Nebulae Creation Both"
      endcase
    TREATY_ELEMENT_TYPE_CANNOT_USE_CLOAKING:
      case elem_value
        1:
          set elem_type_details := "No Cloaking %A"
        2:
          set elem_type_details := "No Cloaking %B"
        3:
          set elem_type_details := "No Cloaking Both"
      endcase
    TREATY_ELEMENT_TYPE_RESOURCE_TARIFF:
      case elem_value
        1:
          set elem_type_details := "Tribute (5%) from %A"
        2:
          set elem_type_details := "Tribute (10%) from %A"
        3:
          set elem_type_details := "Tribute (15%) from %A"
        4:
          set elem_type_details := "Tribute (20%) from %A"
        5:
          set elem_type_details := "Tribute (25%) from %A"
        6:
          set elem_type_details := "Tribute (30%) from %A"
        7:
          set elem_type_details := "Tribute (40%) from %A"
        8:
          set elem_type_details := "Tribute (50%) from %A"
        9:
          set elem_type_details := "Tribute (5%) from %B"
       10:
          set elem_type_details := "Tribute (10%) from %B"
       11:
          set elem_type_details := "Tribute (15%) from %B"
       12:
          set elem_type_details := "Tribute (20%) from %B"
       13:
          set elem_type_details := "Tribute (25%) from %B"
       14:
          set elem_type_details := "Tribute (30%) from %B"
       15:
          set elem_type_details := "Tribute (40%) from %B"
       16:
          set elem_type_details := "Tribute (50%) from %B"
      endcase
    TREATY_ELEMENT_TYPE_SHARE_PLAGUE_CURING:
      case elem_value
        1:
          set elem_type_details := "Share Cures %A"
        2:
          set elem_type_details := "Share Cures %B"
        3:
          set elem_type_details := "Share Cures Both"
      endcase
  endcase

  // Add in empire names when appropriate
  set elem_type_details := Sys_Replace_String(elem_type_details, "%A", entity_name_A, TRUE, FALSE)
  set elem_type_details := Sys_Replace_String(elem_type_details, "%B", entity_name_B, TRUE, FALSE)

  return elem_type_details
end

//------------------------------------------------------------------------
// Do_We_Have_Treaty_Element_With_Player
//------------------------------------------------------------------------
function Do_We_Have_Treaty_Element_With_Player returns boolean
params
  trg_plr:                   long
  elem_type:                 long
  check_elem_value:          boolean
  elem_value:                long
vars
  lst_elem_type:             longlist
  lst_elem_value:            longlist
  list_count:                long
  list_index:                long
  have_elem_type:            boolean := FALSE
begin

  // Get our treaty elements with the target player
  call Sys_Get_Treaty_Elements_Between_Empires(sys_long_Player_ID, trg_plr, lst_elem_type, lst_elem_value)

  // Check for specific treaty element type or value
  set list_count := lst_elem_type.count()

  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      // Check for treaty element type
      if (elem_type = lst_elem_type.get(list_index)) then
        if (check_elem_value) then
          // Check for specific treaty element value if desired
          if (elem_value = lst_elem_value.get(list_index)) then
            set have_elem_type := TRUE
          endif
        else
          set have_elem_type := TRUE
        endif
      endif
      exitwhen (list_index >= list_count) or (have_elem_type)
    endloop
  endif

  return have_elem_type
end

//------------------------------------------------------------------------
// Get_Number_Of_Trade_Treaties
//------------------------------------------------------------------------
function Get_Number_Of_Trade_Treaties returns long
params
vars
  plr_count:                 long
  plr_index:                 long
  pol_status:                long
  trade_count:               long
begin

  // Get the number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Determine how many trade treaties we have
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      if (plr_index <> sys_long_Player_ID) then
        set pol_status := Sys_Empire_Politics_Get_Status_With_Player(sys_long_Player_ID, plr_index)
        // Only check players that we have a treaty with
        if (pol_status = POLITICAL_STATUS_TYPE_TREATY) then
          if Do_We_Have_Treaty_Element_With_Player(plr_index, TREATY_ELEMENT_TYPE_TRADE_PERCENT, FALSE, 0) then
            set trade_count := trade_count + 1
          endif
        endif
      endif
    endfor
  endif

  return trade_count
end

//------------------------------------------------------------------------
// Get_Treaty_Friendship_Value
//------------------------------------------------------------------------
function Get_Treaty_Friendship_Value returns long
params
  trg_plr:                   long
vars
  lst_elem_type:             longlist
  lst_elem_value:            longlist
  elem_type:                 long
  elem_value:                long
  list_count:                long
  list_index:                long
  list_pos:                  long
  friendship_pts:            long
begin

  // Get our treaty elements with the target player
  call Sys_Get_Treaty_Elements_Between_Empires(sys_long_Player_ID, trg_plr, lst_elem_type, lst_elem_value)

  // Check for specific treaty element type or value
  set list_count := lst_elem_type.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      // Check for treaty element type and value
      set elem_type := lst_elem_type.get(list_index)
      set elem_value := lst_elem_value.get(list_index)
      set list_pos := lng_Politics_Treaty_Elements_Allowed_Type.indexof(elem_type) + elem_value - 1
      // Get the treaty element value's in terms of friendship
      if (list_pos > 0) then
        set friendship_pts := friendship_pts + lng_Politics_Treaty_Elements_Allowed_Friendship_Value.get(list_pos)
      endif
    endfor
  endif

  return friendship_pts
end

//------------------------------------------------------------------------
// Get_Non_Aggression_Status
//------------------------------------------------------------------------
function Get_Non_Aggression_Status returns long
params
  trg_plr:                   long
vars
  lst_elem_type:             longlist
  lst_elem_value:            longlist
  elem_type:                 long
  elem_value:                long
  list_count:                long
  list_index:                long
  na_value:                  long := 0
begin

  // Get our treaty elements with the target player
  call Sys_Get_Treaty_Elements_Between_Empires(sys_long_Player_ID, trg_plr, lst_elem_type, lst_elem_value)

  // Check for specific treaty element type or value
  set list_count := lst_elem_type.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      // Check for treaty element type and value
      set elem_type := lst_elem_type.get(list_index)
      set elem_value := lst_elem_value.get(list_index)
      // Get the treaty element value's in terms of friendship
      if (elem_type = TREATY_ELEMENT_TYPE_NON_AGGRESSION) then
        set na_value := elem_value
      endif
    endfor
  endif

  return na_value
end

//------------------------------------------------------------------------
// Difference_In_Known_Empires
//------------------------------------------------------------------------
function Difference_In_Known_Empires returns boolean
params
  plr_A:                     long
  plr_B:                     long
vars
  plr_count:                 long
  plr_index:                 long
  pol_status_A:              long
  pol_status_B:              long
  plr_knows_others:          boolean := FALSE
begin

  // Get the number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Check to see if there are empires that one player knows but the other doesn't
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      if (plr_index <> plr_A) and (plr_index <> plr_B) then
        // Get the political status for each player with the third player
        set pol_status_A := Sys_Empire_Politics_Get_Status_With_Player(plr_A, plr_index)
        set pol_status_B := Sys_Empire_Politics_Get_Status_With_Player(plr_B, plr_index)
        // Player A knows but Player B doesn't
        if (pol_status_A <> POLITICAL_STATUS_TYPE_UNKNOWN) and (pol_status_B = POLITICAL_STATUS_TYPE_UNKNOWN) then
          set plr_knows_others := TRUE
        else
          // Player A doesn't but Player B does
          if (pol_status_A = POLITICAL_STATUS_TYPE_UNKNOWN) and (pol_status_B <> POLITICAL_STATUS_TYPE_UNKNOWN) then
            set plr_knows_others := TRUE
          endif
        endif
      endif
    endfor
  endif

  return plr_knows_others
end

//------------------------------------------------------------------------
// Get_Government_Type_Id
//------------------------------------------------------------------------
function Get_Government_Type_Id returns long
params
  plr_id:                    long
vars
  govt_type:                 string
  govt_id:                   long
begin

  // Get the government type
  set govt_type := Sys_Get_Empire_Government_Type(plr_id)

  // Convert it to a Government Type ID
  case govt_type
    "Anarchy":
      set govt_id := 1
    "Democracy":
      set govt_id := 2
    "Corporate":
      set govt_id := 3
    "Republic":
      set govt_id := 4
    "Oligarchy":
      set govt_id := 5
    "Theocracy":
      set govt_id := 6
    "Monarchy":
      set govt_id := 7
    "Tyranny":
      set govt_id := 8
    "Hive":
      set govt_id := 9
    "Collective":
      set govt_id := 10
  endcase

  return govt_id
end

//------------------------------------------------------------------------
// Get_Society_Type_Id
//------------------------------------------------------------------------
function Get_Society_Type_Id returns long
params
  plr_id:                    long
vars
  society_type:              string
  society_id:                long
begin

  // Get the government type
  set society_type := Sys_Get_Empire_Society_Type(plr_id)

  // Convert it to a Society Type ID
  case society_type
    "Artisans":
      set society_id := 2
    "Berzerkers":
      set society_id := 5
    "Engineers":
      set society_id := 1
    "Farmers":
      set society_id := 3
    "Industrialists":
      set society_id := 3
    "Mechanics":
      set society_id := 1
    "Merchants":
      set society_id := 2
    "Miners":
      set society_id := 3
    "Neutral":
      set society_id := 3
    "Politicians":
      set society_id := 2
    "Refiners":
      set society_id := 3
    "Schemers":
      set society_id := 4
    "Scientists":
      set society_id := 1
    "Suppliers":
      set society_id := 2
    "Traders":
      set society_id := 2
    "Warriors":
      set society_id := 4
    "Xenophobes":
      set society_id := 5
  endcase

  return society_id
end

//------------------------------------------------------------------------
// Compute_Number_Of_Techs_Researched
//------------------------------------------------------------------------
function Compute_Number_Of_Techs_Researched returns long
params
  plr_id:                    long
vars
  tech_index:                long
  tech_id:                   long
  tech_level:                long
  tech_level_count:          long
begin

  // Add up the number of tech levels we've researched for each tech area
  for tech_index := 1 to Sys_Get_Tech_Area_Count() do
    // Get the tech area id
    set tech_id := Sys_Get_Tech_By_Index(tech_index)
    // Add the tech level we've obtained to the total tech level count
    set tech_level := Sys_Get_Empire_Research_Tech_Level(plr_id, tech_id)
    set tech_level_count := tech_level_count + tech_level
  endfor

  return tech_level_count
end

//------------------------------------------------------------------------
// Is_Tech_Area_Available
//------------------------------------------------------------------------
function Is_Tech_Area_Available returns boolean
params
  tech_name:                 string
  tech_level:                long
vars
  tech_id:                   long
  tech_available:            boolean := FALSE
begin

  // Check to see if we have researched any levels in the specified tech area
  set tech_id := Sys_Get_Tech_ID(tech_name)
  if (Sys_Get_Empire_Research_Tech_Level(sys_long_Player_ID, tech_id) >= tech_level) then
    set tech_available := TRUE
  endif

  return tech_available
end

//------------------------------------------------------------------------
// Is_Tech_Area_Visible
//------------------------------------------------------------------------
function Is_Tech_Area_Visible returns boolean
params
  tech_name:                 string
vars
  tech_id:                   long
  tech_visible:              boolean := FALSE
begin

  // Is the tech area available to be researched?
  set tech_id := Sys_Get_Tech_ID(tech_name)
  set tech_visible := Sys_Is_Empire_Research_Tech_Visible(sys_long_Player_ID, tech_id)

  return tech_visible
end
//------------------------------------------------------------------------
// Get_Empire_Tech_Level_By_Name
//------------------------------------------------------------------------
function Get_Empire_Tech_Level_By_Name returns long
params
  tech_name:                 string
vars
  tech_id:                   long
  tech_level:                long
begin

  // Get the current tech level we have researched
  set tech_id := Sys_Get_Tech_ID(tech_name)
  set tech_level := Sys_Get_Empire_Research_Tech_Level(sys_long_Player_ID, tech_id)

  return tech_level
end

//------------------------------------------------------------------------
// Add_Tech_Area_To_Research_List
//------------------------------------------------------------------------
function Add_Tech_Area_To_Research_List returns boolean
params
  tech_name:                 string
  tech_level:                long
  add_tech:                  boolean
vars
begin

  // Add Tech Area to our list
  if (add_tech) then
    call lst_Research_Tech_Area_Name.add(tech_name)
    call lst_Research_Tech_Area_Max_Level.add(tech_level)
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Add_Weapon_To_List
//------------------------------------------------------------------------
function Add_Weapon_To_List returns boolean
params
  weapon_name:               string
  weapon_type:               string
  add_weapon:                boolean
vars
begin

  if (add_weapon) then
    case weapon_type
      "Primary":
        call lst_Primary_Weapon_Name.add(weapon_name)
      "Secondary":
        call lst_Secondary_Weapon_Name.add(weapon_name)
      "Heavy":
        call lst_Heavy_Weapon_Name.add(weapon_name)
      "Special":
        call lst_Special_Weapon_Name.add(weapon_name)
      "Bombardment":
        call lst_Bombardment_Weapon_Name.add(weapon_name)
      "Primary PD":
        call lst_Primary_PD_Weapon_Name.add(weapon_name)
      "Secondary PD":
        call lst_Secondary_PD_Weapon_Name.add(weapon_name)
      "Special PD":
        call lst_Special_PD_Weapon_Name.add(weapon_name)
    endcase
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Is_Vehicle_Size_Available
//------------------------------------------------------------------------
function Is_Vehicle_Size_Available returns boolean
params
  ship_size:                 string
vars
  ship_size_id:              long
  ship_size_available:       boolean := FALSE
begin

   // Get our vehicle size ID
  set ship_size_id := Sys_Get_Vehicle_Size_From_Name(ship_size)

  if Is_Tech_Area_Visible("Organic Technology") then
    set ship_size_id := Sys_Get_Vehicle_Size_From_Name("Organic " + ship_size)
  endif

  if Is_Tech_Area_Visible("Crystalline Technology") then
    set ship_size_id := Sys_Get_Vehicle_Size_From_Name("Crystalline " + ship_size)
  endif

  // Check to see if we have the specified ship size
  if Sys_Is_Vehicle_Size_Available(sys_long_Player_ID, ship_size_id) then
    set ship_size_available := TRUE
  endif

  return ship_size_available
end

//------------------------------------------------------------------------
// Is_Component_Available
//------------------------------------------------------------------------
function Is_Component_Available returns boolean
params
  comp_name:                 string
vars
  comp_id:                   long
begin
  return FALSE

  set comp_id := Sys_Get_Component_With_Name(sys_long_Player_ID, comp_name)
  if (Sys_Is_Component_Available(sys_long_Player_ID, comp_id)) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Is_Facility_Available
//------------------------------------------------------------------------
function Is_Facility_Available returns boolean
params
  facil_id:                  long
vars
begin
  return FALSE

  // Check to see if we have access to a specific facility
  if (Sys_Get_Highest_Facility_Level(sys_long_Player_ID, facil_id) > 0) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Is_Facility_Present_On_Planet
//------------------------------------------------------------------------
function Is_Facility_Present_On_Planet returns boolean
params
  planet_id:                 long
  facil_id:                  long
vars
begin
  return FALSE

  // Do we have a specific facility on this planet?
  if (Sys_Get_Space_Object_Cargo_Facility_Tonnage_Space_Used(planet_id, facil_id) > 0) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Get_Number_Of_Facilities_On_Planet
//------------------------------------------------------------------------
function Get_Number_Of_Facilities_On_Planet returns long
params
  planet_id:                 long
  facil_id:                  long
vars
  space_used:                long
  facil_size:                long
  num_facilities:            long
begin

  // Calculate how many of a specific facility we have on our planet
  set space_used := Sys_Get_Space_Object_Cargo_Facility_Tonnage_Space_Used(planet_id, facil_id)
  set facil_size := Sys_Get_Facility_Tonnage_Space(sys_long_Player_ID, facil_id)
  set num_facilities := Sys_Trunc(space_used / facil_size)

  return num_facilities
end

//------------------------------------------------------------------------
// Can_Facilities_Be_Upgraded
//------------------------------------------------------------------------
function Can_Facilities_Be_Upgraded returns boolean
params
  planet_id:                 long
vars
  facil_count:               long
  facil_index:               long
  lst_facil_id:              longlist
  lst_facil_level:           longlist
  facil_id_to_check:         long
  facil_level_to_check:      long
  upgrade_facilities:        boolean := FALSE
begin

  // Determine how many facilities to upgrade
  call Sys_Get_Space_Object_Cargo_List_Of_Facilities(planet_id, lst_facil_id, lst_facil_level)

  set facil_count := lst_facil_id.count()

  if (facil_count > 0) then
    loop
      set facil_index := facil_index + 1
      set facil_id_to_check := lst_facil_id.get(facil_index)
      set facil_level_to_check := lst_facil_level.get(facil_index)
      // Can the specific facility be upgraded?
      if Sys_Can_Facility_Be_Upgraded(sys_long_Player_ID, facil_id_to_check, facil_level_to_check) then
        set upgrade_facilities := TRUE
      endif
      // Exit if we have found a facility to upgrade
      exitwhen (upgrade_facilities) or (facil_index >= facil_count)
    endloop
  endif

  return upgrade_facilities
end

//------------------------------------------------------------------------
// Get_Number_Of_Facility_Upgrades_To_Add
//------------------------------------------------------------------------
function Get_Number_Of_Facility_Upgrades_To_Add returns long
params
  planet_id:                 long
  facil_id:                  long
vars
  facil_count:               long
  facil_index:               long
  lst_facil_id:              longlist
  lst_facil_level:           longlist
  facil_id_to_check:         long
  facil_level_to_check:      long
  num_to_upgrade:            long
begin

  // Determine how many facilities to upgrade
  call Sys_Get_Space_Object_Cargo_List_Of_Facilities(planet_id, lst_facil_id, lst_facil_level)
  set facil_count := lst_facil_id.count()

  if (facil_count > 0) then
    for facil_index := 1 to facil_count do
      set facil_id_to_check := lst_facil_id.get(facil_index)
      set facil_level_to_check := lst_facil_level.get(facil_index)
      // Can the specific facility be upgraded?
      if (facil_id_to_check = facil_id) then
        if Sys_Can_Facility_Be_Upgraded(sys_long_Player_ID, facil_id_to_check, facil_level_to_check) then
          set num_to_upgrade := num_to_upgrade + 1
        endif
      endif
    endfor
  endif

  return num_to_upgrade
end

//------------------------------------------------------------------------
// Get_Number_Of_Facility_Upgrades_In_Progress
//------------------------------------------------------------------------
function Get_Number_Of_Facility_Upgrades_In_Progress returns long
params
  queue_id:                  long
  facil_id:                  long
vars
  lst_queue_items:           longlist
  lst_count:                 long
  lst_index:                 long
  queue_item_id:             long
  queue_item_type:           long
  item_id:                   long
  num_upgrades:              long
begin

  // Get a list of items under construction
 call Sys_Get_Construction_Queue_Items_List(queue_id, lst_queue_items)

 // Look through the queue's items
  set lst_count := lst_queue_items.count()
  if (lst_count > 0) then
    for lst_index := 1 to lst_count do
      set queue_item_id := lst_queue_items.get(lst_index)
      set queue_item_type := Sys_Get_Construction_Queue_Item_Type(queue_id, queue_item_id)
      // Check our facility upgrades
      if (queue_item_type = CONSTRUCTION_ITEM_TYPE_UPGRADE_FACILITY) then
        set item_id := Sys_Get_Construction_Queue_Item_Upgrade_ID(queue_id, queue_item_id)
        // Count the number of specific facility upgrades in progress
        if (facil_id = item_id) then
          set num_upgrades := num_upgrades + 1
        endif
      endif
    endfor
  endif

  return num_upgrades
end

//------------------------------------------------------------------------
// Get_Total_Number_Of_Facilities_On_Planet
//------------------------------------------------------------------------
function Get_Total_Number_Of_Facilities_On_Planet returns long
params
  planet_id:                 long
vars
  space_used:                long
  num_facilities:            long
begin

  // Calculate how many of a specific facility we have on our planet
  set space_used := Sys_Get_Space_Object_Facility_Total_Space(planet_id) - Sys_Get_Space_Object_Facility_Space_Remaining(planet_id)
  set num_facilities := Sys_Trunc(space_used / 1000)

  return num_facilities
end

//------------------------------------------------------------------------
// Calculate_Planet_Pollution
//------------------------------------------------------------------------
function Calculate_Planet_Pollution returns long
params
  planet_id:                 long
vars
  lst_facility_id:           longlist
  lst_facility_level:        longlist
  facility_count:            long
  facility_index:            long
  facility_id:               long
  facility_name:             string
  facility_level:            long
  tech_id:                   long
  tech_level:                long
  pollution_pts:             long
begin

  // Get a list of the planet's facilities
  call Sys_Get_Space_Object_Cargo_List_Of_Facilities(planet_id, lst_facility_id, lst_facility_level)
  set facility_count := lst_facility_id.count()
  // Examine the colony's facilities
  if (facility_count > 0) then
    for facility_index := 1 to facility_count do
      set facility_id := lst_facility_id.get(facility_index)
      set facility_name := Sys_Get_Facility_Name(facility_id)
      set facility_level := lst_facility_level.get(facility_index)
      // Assign pollution points based on the facilities present
      case facility_name
        "Space Yard Facility":
          set pollution_pts := pollution_pts + 5
        "Mineral Miner Facility":
          set pollution_pts := pollution_pts + 2
        "Organics Farm Facility":
          set pollution_pts := pollution_pts + 1
        "Radioactives Extraction Facility":
          set pollution_pts := pollution_pts + 2
        "Monolith Facility":
          set pollution_pts := pollution_pts + 3
        "Mineral Scanner":
          set pollution_pts := pollution_pts + 5
        "System Mineral Scanner":
          set pollution_pts := pollution_pts + 10
        "Hybrid Eco-Farms":
          set pollution_pts := pollution_pts + 3
        "System Eco-Farms":
          set pollution_pts := pollution_pts + 5
        "Radioactives Collider":
          set pollution_pts := pollution_pts + 5
        "System Radioactives Collider":
          set pollution_pts := pollution_pts + 10
        "Components Factory":
          set pollution_pts := pollution_pts + 5
        "System Robotoid Factory":
          set pollution_pts := pollution_pts + 10
        "Ultra-Recycler":
          set pollution_pts := pollution_pts + 5
        "Resource Converter":
          set pollution_pts := pollution_pts + 10
        "Climate Control Facility":
          set pollution_pts := pollution_pts - (10 + (facility_level - 1) * 5)
      endcase
    endfor
  endif

  // Adjust pollution points to the planet's size
  case Sys_Get_Planet_Size(planet_id)
    "Tiny":
      set pollution_pts := Sys_Trunc(pollution_pts * 5.00)
    "Small":
      set pollution_pts := Sys_Trunc(pollution_pts * 2.50)
    "Medium":
      set pollution_pts := Sys_Trunc(pollution_pts * 1.67)
    "Large":
      set pollution_pts := Sys_Trunc(pollution_pts * 1.25)
    "Huge":
      set pollution_pts := Sys_Trunc(pollution_pts * 1.00)
    "Ringworld":
      set pollution_pts := Sys_Trunc(pollution_pts * 0.25)
    "Sphereworld":
      set pollution_pts := Sys_Trunc(pollution_pts * 0.10)
  endcase

  // Adjust pollution points based on environmental achievements
  set tech_id := Sys_Get_Tech_ID("Environment")
  set tech_level := Sys_Get_Empire_Research_Tech_Level(sys_long_Player_ID, tech_id)
  // Adjust pollution points
  set pollution_pts := Sys_Max_Long(0, pollution_pts - (tech_level * 3))

  return pollution_pts
end

//------------------------------------------------------------------------
// List_Planet_Facilities_For_Debug
//------------------------------------------------------------------------
function List_Planet_Facilities_For_Debug returns boolean
params
  planet_id:                 long
vars
  lst_facility_id:           longlist
  lst_facility_level:        longlist
  facility_count:            long
  facility_index:            long
  facility_id:               long
  facility_name:             string
  facility_level:            long
begin

  // Get a list of the planet's facilities
  call Sys_Get_Space_Object_Cargo_List_Of_Facilities(planet_id, lst_facility_id, lst_facility_level)
  set facility_count := lst_facility_id.count()
  // Print out the planet's facilities
  if (facility_count > 0) then
    for facility_index := 1 to facility_count do
      set facility_id := lst_facility_id.get(facility_index)
      set facility_name := Sys_Get_Facility_Name(facility_id)
      set facility_level := lst_facility_level.get(facility_index)
      // Debug output
      call Sys_Debug_Print("System", "          - " + facility_name + " (" + Sys_Convert_Long_To_String(facility_level) + ")")
    endfor
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Is_Facility_Present_In_System
//------------------------------------------------------------------------
function Is_Facility_Present_In_System returns boolean
params
  sys_id:                    long
  facility_id:               long
vars
begin
  return FALSE

  // Do we have a specific facility in this system?
  if (Sys_Get_Facility_Count_In_System(sys_long_Player_ID, sys_id, facility_id) > 0) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Is_Facility_Queued_On_Planet
//------------------------------------------------------------------------
function Is_Facility_Queued_On_Planet returns boolean
params
  queue_id:                    long
  facility_name:               string
vars
begin
  return FALSE

  // Do we have a specific facility queued on this planet?
  if (Sys_Get_Construction_Queue_Specific_Facility_Count(queue_id, facility_name) > 0) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Is_Facility_Ability_Queued_On_Planet
//------------------------------------------------------------------------
function Is_Facility_Ability_Queued_On_Planet returns boolean
params
  queue_id:                    long
  ability_name:                string
vars
begin
  return FALSE

  // Do we have a specific facility queued on this planet?
  if (Sys_Get_Construction_Queue_Ability_Facility_Count(queue_id, ability_name) > 0) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Is_Facility_Queued_In_System
//------------------------------------------------------------------------
function Is_Facility_Queued_In_System returns boolean
params
  sys_id:                    long
  facility_name:             string
vars
begin
  return FALSE

  // Do we have a specific facility queued in this system?
  if (Sys_Get_System_Queues_Specific_Facility_Count(sys_long_Player_ID, sys_id, facility_name) > 0) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Is_Facility_Ability_Queued_In_System
//------------------------------------------------------------------------
function Is_Facility_Ability_Queued_In_System returns boolean
params
  sys_id:                    long
  ability_name:              string
vars
begin
  return FALSE

  // Do we have a specific facility queued in this system?
  if (Sys_Get_System_Queues_Ability_Facility_Count(sys_long_Player_ID, sys_id, ability_name) > 0) then
    return TRUE
  endif

end

//------------------------------------------------------------------------
// Get_Number_Of_Facilities_In_System
//------------------------------------------------------------------------
function Get_Number_Of_Facilities_In_System returns long
params
  sys_id:                    long
  facil_id:                  long
vars
  num_facilities:            long := 0
begin

  // Get the number of the specific facility in this system
  set num_facilities := Sys_Get_Facility_Count_In_System(sys_long_Player_ID, sys_id, facil_id)

  return num_facilities
end

//------------------------------------------------------------------------
// Is_System_Protected
//------------------------------------------------------------------------
function Is_System_Protected returns boolean
params
  sys_id:                    long
vars
  list_count:                long
  list_index:                long
  system_protected:          boolean := FALSE
begin

  // Get Number of Players
  set list_count := Sys_Get_Number_Of_Players()

  // Is the system protected from stellar manipulation?
  loop
    set list_index := list_index + 1
    // Check to see if any players have a System Gravitational Shield in place
    if (Sys_Get_Facility_Count_In_System(list_index, sys_id, lng_facility_id_sys_shield) > 0) then
      set system_protected := TRUE
    endif
    exitwhen (list_index >= list_count) or (system_protected)
  endloop

  return system_protected
end

//------------------------------------------------------------------------
// Get_Total_Number_Of_Facilities_In_System
//------------------------------------------------------------------------
function Get_Total_Number_Of_Facilities_In_System returns long
params
  sys_id:                    long
vars
  index:                     long
  num_facilities:            long
begin

  // Add up all the facilities that are in this system
  for index := 1 to 50 do
    set num_facilities := num_facilities + Sys_Get_Facility_Count_In_System(sys_long_Player_ID, sys_id, index)
  endfor

  return num_facilities
end

//------------------------------------------------------------------------
// Get_General_AI_Design_Type
//------------------------------------------------------------------------
function Get_General_AI_Design_Type returns string
params
  ai_design_type:            string
vars
  general_design_type:       string
begin

  // Convert our ship's design type into a general design type
  set general_design_type := ai_design_type

  if (ai_design_type = "Ship (Attack S)") or (ai_design_type = "Ship (Attack M)") or (ai_design_type = "Ship (Attack L)") then
    set general_design_type := "Ship (Attack)"
  endif
  if (ai_design_type = "Ship (Defense S)") or (ai_design_type = "Ship (Defense M)") or (ai_design_type = "Ship (Defense L)") then
    set general_design_type := "Ship (Defense)"
  endif
  if (ai_design_type = "Ship (Seeker S)") or (ai_design_type = "Ship (Seeker M)") or (ai_design_type = "Ship (Seeker L)") then
    set general_design_type := "Ship (Seeker)"
  endif
  if (ai_design_type = "Carrier (Fighter S)") or (ai_design_type = "Carrier (Fighter M)") or (ai_design_type = "Carrier (Fighter L)") then
    set general_design_type := "Carrier (Fighter)"
  endif
  if (ai_design_type = "Carrier (Drone S)") or (ai_design_type = "Carrier (Drone M)") or (ai_design_type = "Carrier (Drone L)") then
    set general_design_type := "Carrier (Drone)"
  endif
  if (ai_design_type = "Base (Defense S)") or (ai_design_type = "Base (Defense L)") then
    set general_design_type := "Base (Defense)"
  endif
  if (ai_design_type = "Weapon Platform (S)") or (ai_design_type = "Weapon Platform (M)") or (ai_design_type = "Weapon Platform (L)") then
    set general_design_type := "Weapon Platform"
  endif
  if (ai_design_type = "Weapon Platform (Seeker S)") or (ai_design_type = "Weapon Platform (Seeker M)") or (ai_design_type = "Weapon Platform (Seeker L)") then
    set general_design_type := "Weapon Platform (Seeker)"
  endif

  return general_design_type
end

//------------------------------------------------------------------------
// Get_Number_Of_Fleets
//------------------------------------------------------------------------
function Get_Number_Of_Fleets returns long
params
vars
  lst_ships:                 longlist
  ship_count:                long
  ship_index:                long
  ship_id:                   long
  fleet_id:                  long
  highest_fleet_id:          long := 0
begin

  set ship_count := Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_SHIP, lst_ships, TRUE, FALSE, sys_long_Player_ID)

  // Check all our ships for the highest fleet ID (workaround for possible fleet index bug)
  if (ship_count > 0) then
    for ship_index := 1 to ship_count do
      set ship_id := lst_ships.get(ship_index)
      set fleet_id := Sys_Get_Space_Object_Fleet(ship_id)
      // Find our highest fleet id
      if (fleet_id > highest_fleet_id) then
        set highest_fleet_id := fleet_id
      endif
    endfor
  endif

  return highest_fleet_id
end

//------------------------------------------------------------------------
// Get_Task_Force_Role
//------------------------------------------------------------------------
function Get_Task_Force_Role returns string
params
  ship_id:                   long
vars
  task_force_role:           long
  task_force_role_name:      string
begin

  // Get our ship's task force role
  set task_force_role := Sys_Get_Space_Object_Task_Force_Role(ship_id)

  // Convert the role ID to a name
  case task_force_role
    TASK_FORCE_ROLE_CORE:
      set task_force_role_name := "Core"
    TASK_FORCE_ROLE_ESCORT:
      set task_force_role_name := "Escort"
    TASK_FORCE_ROLE_PICKET:
      set task_force_role_name := "Picket"
  endcase

  return task_force_role_name
end

//------------------------------------------------------------------------
// Get_Task_Force_Ship_Count
//------------------------------------------------------------------------
function Get_Task_Force_Ship_Count returns string
params
  fleet_id:                  long
  task_force_id:             long
vars
  task_force_ship_list:      longlist
begin

  // Get a list of the task force ships
  call Sys_Get_Empire_Fleet_Taskforce_Ship_Ids(sys_long_Player_ID, fleet_id, task_force_id, task_force_ship_list)

  return task_force_ship_list.count()
end

//------------------------------------------------------------------------
// Get_Component_Index
//------------------------------------------------------------------------
function Get_Component_Index returns long
params
  ship_id:                   long
  comp_id:                   long
vars
  comp_count:                long
  comp_index:                long
  comp_pos:                  long
begin

  // Get the number of components on our ship
  set comp_count := Sys_Get_Space_Object_Comp_Count(ship_id)

  if (comp_count > 0) then
    loop
      set comp_index := comp_index + 1
      // Check for the wanted component's position on our ship
      if (Sys_Get_Space_Object_Comp_Info_Comp_ID(ship_id, comp_index) = comp_id) then
        set comp_pos := comp_index
      endif
      exitwhen (comp_pos > 0) or (comp_index >= comp_count)
    endloop
  endif

  return comp_pos
end

//------------------------------------------------------------------------
// Get_Component_Level
//------------------------------------------------------------------------
function Get_Component_Level returns long
params
  ship_id:                   long
  comp_id:                   long
vars
  comp_count:                long
  comp_index:                long
  comp_level:                long
begin

  // Get the number of components on our ship
  set comp_count := Sys_Get_Space_Object_Comp_Count(ship_id)

  if (comp_count > 0) then
    loop
      set comp_index := comp_index + 1
      // Check for the wanted component's level on our ship
      if (Sys_Get_Space_Object_Comp_Info_Comp_ID(ship_id, comp_index) = comp_id) then
        set comp_level := Sys_Get_Space_Object_Comp_Info_Comp_Level(ship_id, comp_index)
      endif
      exitwhen (comp_level > 0) or (comp_index >= comp_count)
    endloop
  endif

  return comp_level
end

//------------------------------------------------------------------------
// Is_Component_Damaged
//------------------------------------------------------------------------
function Is_Component_Damaged returns boolean
params
  ship_id:                   long
  comp_name:                 string
vars
  comp_id:                   long
  comp_count:                long
  comp_index:                long
  comp_damage:               long
  comp_structure:            long
  comp_inoperable:           boolean
begin

  // Get the number of components on our ship
  set comp_count := Sys_Get_Space_Object_Comp_Count(ship_id)

  // Get the component's ID to check for damage
  set comp_id := Sys_Get_Component_With_Name(sys_long_Player_ID, comp_name)

  if (comp_count > 0) then
    for comp_index := 1 to comp_count do
      // Check to see if the component is damaged
      if (Sys_Get_Space_Object_Comp_Info_Comp_ID(ship_id, comp_index) = comp_id) then
        set comp_damage := Sys_Get_Space_Object_Comp_Info_Comp_Tonnage_Damage(ship_id, comp_index)
        set comp_structure := Sys_Get_Space_Object_Comp_Info_Comp_Tonnage_Structure(ship_id, comp_index)
        // Is the component inoperable?
        if (comp_damage > comp_structure * 0.50) then
          set comp_inoperable := TRUE
        endif
      endif
    endfor
  endif

  return comp_inoperable
end

//------------------------------------------------------------------------
// Get_Mine_Sweep_Count
//------------------------------------------------------------------------
function Get_Mine_Sweep_Count returns long
params
  ship_id:                   long
vars
  comp_id:                   long
  comp_count:                long
  comp_index:                long
  comp_damage:               long
  comp_structure:            long
  comp_level:                long
  mine_sweep_count:          long
begin

  // Get the number of components on our ship
  set comp_count := Sys_Get_Space_Object_Comp_Count(ship_id)

  // Count the number of operable Mine Sweeper components our ship has
  set comp_id := Sys_Get_Component_With_Name(sys_long_Player_ID, "Mine Sweeper")

  if (comp_count > 0) then
    for comp_index := 1 to comp_count do
      // Check to see if the Mine Sweeper component is damaged
      if (Sys_Get_Space_Object_Comp_Info_Comp_ID(ship_id, comp_index) = comp_id) then
        set comp_damage := Sys_Get_Space_Object_Comp_Info_Comp_Tonnage_Damage(ship_id, comp_index)
        set comp_structure := Sys_Get_Space_Object_Comp_Info_Comp_Tonnage_Structure(ship_id, comp_index)
        // Only count components that are not damaged...
        if (comp_damage < comp_structure * 0.50) then
          set comp_level := Sys_Get_Space_Object_Comp_Info_Comp_Level(ship_id, comp_index)
          // Determine the number of mines the component sweeps based on its level
          set mine_sweep_count := mine_sweep_count + (comp_level + 5)
        endif
      endif
    endfor
  endif

  return mine_sweep_count
end

//------------------------------------------------------------------------
// Can_Ship_Repair_Itself
//------------------------------------------------------------------------
function Can_Ship_Repair_Itself returns boolean
params
  ship_id:                   long
vars
  design_id:                 long
  repairs_itself:            boolean := FALSE
begin

  // Get our ship's design ID
  set design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)

  // Can the ship have a repair bay?
  set repairs_itself := Sys_Does_Vehicle_Design_Have_Ability_With_Name(sys_long_Player_ID, design_id, "Tonnage Repair Ship")

  return repairs_itself
end

//------------------------------------------------------------------------
// Does_Ship_Need_Repair
//------------------------------------------------------------------------
function Does_Ship_Need_Repair returns boolean
params
  ship_id:                   long
  min_dmg_pct:               long
  must_have_weapons:         boolean
  must_have_movement:        boolean
  must_repair:               boolean
vars
  ship_movement:             long
  ship_sys_loc:              long
  ship_sect_loc:             long
  num_comps:                 long
  dmg_comps:                 long
  dmg_pct:                   long
  SY_present:                boolean := FALSE
  needs_repair:              boolean := FALSE
begin

  // Get our ship's details
  set ship_movement := Sys_Get_Space_Object_Maximum_Movement(ship_id)
  set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
  set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

  // Get our ship's damage
  set num_comps := Sys_Get_Space_Object_Comp_Count(ship_id)
  set dmg_comps := Sys_Get_Space_Object_Number_Of_Damaged_Components(ship_id)
  set dmg_pct := Sys_Trunc((dmg_comps / num_comps) * 100)

  // Is there a Space Yard Present?
  set SY_present := Sys_Is_Space_Yard_At_Location(sys_long_Player_ID, ship_sys_loc, ship_sect_loc)

  // Adjust minimum damage for repair based on SY
  if (SY_present) then
    set min_dmg_pct := Sys_Divide_Long(min_dmg_pct, 2)
  endif

  if (dmg_pct > 0) then
    // Debug output
    call Sys_Debug_Print("Ships", "    - Damage = " + Sys_Convert_Long_To_String(dmg_pct) + "%")

    // Pending
    if (dmg_pct >= min_dmg_pct) then
      set needs_repair := TRUE
      // Debug output
      call Sys_Debug_Print("Ships", "      - Repair required (Damage amount above target)")
    endif

    // Our ship has lost its functional or critical components and must repair
    if (must_repair) or Sys_Has_Space_Object_Lost_Critical_Components(ship_id) then
      set needs_repair := TRUE
      // Debug output
      call Sys_Debug_Print("Ships", "      - Repair required (critical components damaged)")
    endif

    // Does our ship need its weapons?
    if (must_have_weapons) then
      if (Sys_Get_Space_Object_Number_Of_Undamaged_Weapons(ship_id) = 0) then
        set needs_repair := TRUE
        // Debug output
        call Sys_Debug_Print("Ships", "      - Repair required (weapons damaged)")
      endif
    endif

    // Does our ship need movement?
    if (must_have_movement) then
      if (ship_movement = 0) then
        set needs_repair := TRUE
        // Debug output
        call Sys_Debug_Print("Ships", "      - Repair required (No movement)")
      endif
    endif
  endif

  return needs_repair
end

//------------------------------------------------------------------------
// Do_Ships_In_Fleet_Need_Repair
//------------------------------------------------------------------------
function Do_Ships_In_Fleet_Need_Repair returns boolean
params
  fleet_id:                  long
vars
  lst_fleet_ships:           longlist
  list_count:                long
  list_index:                long
  ship_id:                   long
  ship_num_comps:            long
  total_ship_num_comps:      long
  ship_dmg_comps:            long
  total_ship_dmg_comps:      long
  repair_count:              long
  repair_fleet:              boolean := FALSE
begin

  // Get a list of ships in our fleet
  call Sys_Get_Empire_Fleet_Ship_List(sys_long_Player_ID, fleet_id, lst_fleet_ships)
  set list_count := lst_fleet_ships.count()

  // Quickly check if our ship's design is significantly obsolete
  if (list_count > 0) then
    for list_index := 1 to list_count do
      set ship_id := lst_fleet_ships.get(list_index)
      set ship_num_comps := Sys_Get_Space_Object_Comp_Count(ship_id)
      set total_ship_num_comps := total_ship_num_comps + ship_num_comps
      set ship_dmg_comps := Sys_Get_Space_Object_Number_Of_Damaged_Components(ship_id)
      set total_ship_dmg_comps := total_ship_dmg_comps + ship_dmg_comps
      // Count total number of ships requiring repair
      if (ship_dmg_comps > ship_num_comps * 0.1) then
        set repair_count := repair_count + 1
      endif
    endfor
  endif

  // Have our fleet repair if most of the ships are damaged
  if (total_ship_dmg_comps > total_ship_num_comps * 0.2) and (repair_count > list_count * 0.5) then
    set repair_fleet := TRUE
  endif

  return repair_fleet
end

//------------------------------------------------------------------------
// Calculate_Retrofit_Cost_Difference
//------------------------------------------------------------------------
function Calculate_Retrofit_Cost_Difference returns long
params
  ship_id:                   long
vars
  ai_design_type:            string
  this_design_id:            long
  this_design_cost:          resources
  this_design_total_cost:    real
  best_design_id:            long
  best_design_cost:          resources
  best_design_total_cost:    real
  retrofit_pct_diff:         long := 0
begin

  // Get our ship's details
  set ai_design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
  set this_design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
  set this_design_cost := Sys_Get_Vehicle_Design_Cost(this_design_id)
  set this_design_total_cost := this_design_cost.get(RESOURCE_TYPE_MINERALS) + this_design_cost.get(RESOURCE_TYPE_ORGANICS) + this_design_cost.get(RESOURCE_TYPE_RADIOACTIVES)
  set best_design_id := Sys_Get_Latest_Vehicle_Design_Of_AI_Type(sys_long_Player_ID, ai_design_type)
  set best_design_cost := Sys_Get_Vehicle_Design_Cost(best_design_id)
  set best_design_total_cost := best_design_cost.get(RESOURCE_TYPE_MINERALS) + best_design_cost.get(RESOURCE_TYPE_ORGANICS) + best_design_cost.get(RESOURCE_TYPE_RADIOACTIVES)
  
  // Calculate the retrofit cost difference
  if (this_design_id <> best_design_id) then
    set retrofit_pct_diff := Sys_Trunc(100 * (this_design_total_cost - best_design_total_cost) / this_design_total_cost)
  endif

  if (retrofit_pct_diff < 0) then
    set retrofit_pct_diff := retrofit_pct_diff * -1
  endif

  return retrofit_pct_diff
end

//------------------------------------------------------------------------
// Do_Ships_In_Fleet_Need_Retrofit
//------------------------------------------------------------------------
function Do_Ships_In_Fleet_Need_Retrofit returns boolean
params
  fleet_id:                  long
  retrofit_age:              long
  retrofit_pct:              long
vars
  lst_fleet_ships:           longlist
  list_count:                long
  list_index:                long
  ship_id:                   long
  ship_design_id:            long
  ship_design_age:           long
  retrofit_cost_pct:         long
  retrofit_count:            long
  retrofit_fleet:            boolean := FALSE
begin

  // Get a list of ships in our fleet
  call Sys_Get_Empire_Fleet_Ship_List(sys_long_Player_ID, fleet_id, lst_fleet_ships)
  set list_count := lst_fleet_ships.count()

  // Quickly check if our ship's design is significantly obsolete
  if (list_count > 0) then
    for list_index := 1 to list_count do
      set ship_id := lst_fleet_ships.get(list_index)
      set ship_design_id := Sys_Get_Space_Object_Vehicle_Design_ID(ship_id)
      // Is our ship's design obsolete?
      if Sys_Is_Vehicle_Design_Obsolete(ship_design_id) then
        set ship_design_age := sys_long_Game_Date - Sys_Get_Vehicle_Design_Creation_Date(sys_long_Player_ID, ship_design_id)
        // If our ship is more than # turns old with an obsolete design type, then consider it needs to be retrofit
        if (ship_design_age > retrofit_age) then
          set retrofit_cost_pct := Calculate_Retrofit_Cost_Difference(ship_id)
          // Don't count ships less than the minimum or maximum cost to retrofit
          if (retrofit_cost_pct > lng_Retrofit_Min_Cost_Difference) and (retrofit_cost_pct < lng_Retrofit_Max_Cost_Difference) then
            set retrofit_count := retrofit_count + 1
          endif
        endif
      endif
    endfor
  endif

  // Debug
  call Sys_Debug_Print("Ships", "      - Retrofit Count = " + Sys_Convert_Long_To_String(retrofit_count) + "/" + Sys_Convert_Long_To_String(list_count))

  // Have our fleet hold its position to retrofit more ships
  if ((retrofit_count / list_count * 100) > retrofit_pct) then
    set retrofit_fleet := TRUE
    // Debug
    call Sys_Debug_Print("Ships", "        - Fleet retrofit recommended")
  endif

  return retrofit_fleet
end

//------------------------------------------------------------------------
// Find_Alternative_Design_Type_For_Retrofit
//------------------------------------------------------------------------
function Find_Alternative_Design_Type_For_Retrofit returns string
params
  ai_design_type:            string
  design_size_id:            long
vars
  gen_design_type:           string
  lst_alt_design_type:       stringlist
  alt_design_type:           string
  alt_gen_design_type:       string
  alt_design_id:             long
  alt_design_size_id:        long
  list_count:                long
  list_index:                long
  list_pos:                  long
  ideal_match:               boolean := FALSE
  new_design_type:           string
begin

  // Get our ship's general design type
  set gen_design_type := Get_General_AI_Design_Type(ai_design_type)

  // Create a list of alternate design types
  call lst_alt_design_type.add("Ship (Attack S)")
  call lst_alt_design_type.add("Ship (Attack M)")
  call lst_alt_design_type.add("Ship (Attack L)")
  call lst_alt_design_type.add("Ship (Defense S)")
  call lst_alt_design_type.add("Ship (Defense M)")
  call lst_alt_design_type.add("Ship (Defense L)")
  call lst_alt_design_type.add("Ship (Seeker S)")
  call lst_alt_design_type.add("Ship (Seeker M)")
  call lst_alt_design_type.add("Ship (Seeker L)")

  // Find an alternate design type using the same hull size
  set list_count := lst_alt_design_type.count()
  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      // Look for a match in terms of size and general design type
      set alt_design_type := lst_alt_design_type.get(list_index)
      set alt_gen_design_type := Get_General_AI_Design_Type(alt_design_type)
      set alt_design_id := Sys_Get_Latest_Vehicle_Design_Of_AI_Type(sys_long_Player_ID, alt_design_type)
      set alt_design_size_id := Sys_Get_Vehicle_Design_Size_ID(alt_design_id)
      // Is the alternate design the correct size?
      if (design_size_id = alt_design_size_id) then
        // Is it an ideal match (size and general design type match)
        if (not ideal_match) and (gen_design_type = alt_gen_design_type) then
          set list_pos := list_index
          set ideal_match := TRUE
        else
          set list_pos := list_index
        endif
      endif

      exitwhen (list_index >= list_count) or (ideal_match)
    endloop
  endif

  if (list_pos > 0) then
    set new_design_type := lst_alt_design_type.get(list_pos)
  endif

  return new_design_type
end

//------------------------------------------------------------------------
// Is_Ship_Design_Type_In_Demand
//------------------------------------------------------------------------
function Is_Ship_Design_Type_In_Demand returns boolean
params
  ship_id:                   long
  design_type:               string
vars
  ai_design_type:            string
  index:                     long
  num_built:                 long
  num_wanted:                long
  num_queued:                long
  dmd_reduction:             long
  dmd_amount:                long
  design_in_demand:          boolean := TRUE
begin

  // Get our ship or design's details
  if (ship_id > 0) then
    set ai_design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
  endif

  if (design_type <> "") then
    set ai_design_type := design_type
  endif

  // Update our vehicle design statistics
  call Sys_Compute_AI_Design_Type_Statistics(sys_long_Player_ID)

  // Calculate the demand for the selected design type
  set index := lst_AI_Design_Type_Name.indexof(ai_design_type)

  if (index > 0) then
    set num_built := Sys_AI_Design_Type_Stats_Get_Vehicle_Count(ai_design_type)
    set num_queued := Sys_AI_Design_Type_Stats_Get_Queue_Items_Count(ai_design_type)
    set num_wanted := lst_AI_Design_Type_Num_Wanted.get(index)
    set dmd_reduction := lst_AI_Design_Type_Vehicle_Demand.get(index) * (num_built + num_queued)
    set dmd_amount := lst_AI_Design_Type_Vehicle_Demand.get(index) * num_wanted - dmd_reduction
  endif

  // If there is a negative demand, we don't need more of this design type
  if (dmd_amount < 0) then
    set design_in_demand := FALSE
  endif

  return design_in_demand
end

//------------------------------------------------------------------------
// Is_Design_ID_Ours
//------------------------------------------------------------------------
function Is_Design_ID_Ours returns boolean
params
  design_id:                 long
vars
  design_count:              long
  design_index:              long
  design_id_match:           boolean := FALSE
begin

  // Check to see if the ship's design ID matches one of our design IDs
  set design_count := Sys_Get_Player_Designs_Count(sys_long_Player_ID)

  if (design_count > 0) then
    loop
      set design_index := design_index + 1
      // Does the ship design id match?
      if (design_id = Sys_Get_Player_Design_ID(sys_long_Player_ID, design_index)) then
        set design_id_match := TRUE
      endif
      exitwhen (design_index >= design_count) or (design_id_match)
    endloop
  endif

  return design_id_match
end

//------------------------------------------------------------------------
// Calculate_Space_Object_Strength
//------------------------------------------------------------------------
function Calculate_Space_Object_Strength returns long
params
  sobj_id:                   long
vars
  sobj_type:                 long
  sobj_armor:                long
  sobj_shields:              long
  sobj_weapons:              long
  sobj_structure:            long
  sobj_strength:             long := 0
begin

  // Get the space object's shields, armor and weapon damage
  set sobj_shields := Sys_Get_Space_Object_Current_Shields(sobj_id)
  set sobj_armor := Sys_Get_Space_Object_Current_Armor_Structure(sobj_id)
  set sobj_weapons := Sys_Get_Space_Object_Total_Weapon_Damage(sobj_id)

  // Don't count structure as much for planets due to population and facility contributions
  // Don't count armor as structure
  if (Sys_Get_Space_Object_Type(sobj_id) = SPACE_OBJECT_TYPE_PLANET) then
    set sobj_structure := Sys_Divide_Long(Sys_Get_Space_Object_Total_Tonnage_Structure(sobj_id) - sobj_armor, 10)
  else
    set sobj_structure := Sys_Get_Space_Object_Total_Tonnage_Structure(sobj_id) - sobj_armor
  endif

  // Calculate the space object's final strength
  set sobj_strength := sobj_structure + (sobj_armor * 2) + (sobj_shields * 2) + (sobj_weapons * 10)
  set sobj_strength := Sys_Divide_Long(sobj_strength, 10)

  return sobj_strength
end

//------------------------------------------------------------------------
// Calculate_Sector_Strength
//------------------------------------------------------------------------
function Calculate_Sector_Strength returns long
params
  dest_sys:                  long
  dest_sect:                 long
  our_empire:                boolean
  all_empires:               boolean
  all_enemies:               boolean
vars
  sobj_list:                 longlist
  sobj_id:                   long
  sobj_owner:                long
  sobj_strength:             long
  count_sobj:                boolean := FALSE
  total_strength:            long
  list_count:                long
  list_index:                long
begin

  // Make a list of all visible objects in the sector
  call Sys_Get_List_Of_Visible_Space_Objects_In_Sector(sys_long_Player_ID, 0, dest_sys, dest_sect, sobj_list)

  // Add up the strength of all space objects in the sector
  set list_count := sobj_list.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      // Note the owner
      set sobj_id := sobj_list.get(list_index)
      set sobj_owner := Sys_Get_Space_Object_Owner(sobj_id)
      set count_sobj := FALSE
      // Should we consider this object towards the total strength?
      if (our_empire) and (sobj_owner = sys_long_player_ID) then
        set count_sobj := TRUE
      endif
      if (all_empires) and (sobj_owner <> sys_long_player_ID) then
        set count_sobj := TRUE
      endif
      if (all_enemies) and Sys_Empire_Politics_Is_Player_Enemy(sys_long_Player_ID, sobj_owner) then
        set count_sobj := TRUE
      endif
      // Get the space object's strength and add it to the total
      if (count_sobj) then
        set sobj_strength := Calculate_Space_Object_Strength(sobj_id)
        set total_strength := total_strength + sobj_strength
      endif
    endfor
  endif

  return total_strength
end

//------------------------------------------------------------------------
// Get_Unit_Group_Type
//------------------------------------------------------------------------
function Get_Unit_Group_Type returns string
params
  unit_group_id:             long
vars
  unit_id:                   long
  unit_group_type:           string
  unit_group_name:           string
begin

  // Determine which units our unit group contains
  set unit_id := Sys_Get_Space_Object_Cargo_Item_ID(unit_group_id, 1)
  set unit_group_name := Sys_Get_Space_Object_Name(unit_group_id)
  set unit_group_type := Sys_Get_Space_Object_Cargo_Item_Unit_Type(unit_group_id, unit_id)

  // Debug output
  call Sys_Debug_Print("Ships", "        - Group check = " + unit_group_type)

  // Backup if first group check fails
  if (unit_group_type = "") then
    if (Sys_Pos_String("Fighter", unit_group_name) > 0) then
      set unit_group_type := "Fighter"
    endif
    if (Sys_Pos_String("Satellite", unit_group_name) > 0) then
      set unit_group_type := "Satellite"
    endif
    if (Sys_Pos_String("Drone", unit_group_name) > 0) then
      set unit_group_type := "Drone"
    endif
    if (Sys_Pos_String("Mine", unit_group_name) > 0) then
      set unit_group_type := "Mine"
    endif
  endif

  // Might be a group echo from recovered units
  if (unit_group_type = "") then
    set unit_group_type := "Phantom"
  endif

  return unit_group_type
end

//------------------------------------------------------------------------
// Get_Mine_Group_Count
//------------------------------------------------------------------------
function Get_Mine_Group_Count returns long
params
  sys_loc:                   long
  sect_loc:                  long
vars
  plr_list:                  longlist
  plr_count:                 long
  plr_index:                 long
  plr_id:                    long
  mine_count:                long
  mine_count_enemy:          long
begin

  // Get all the players in this system
  call Sys_Get_Players_In_System_List(plr_list, sys_loc)

  // Count the number of mines in the sector that can damage our vehicles
  set plr_count := plr_list.count()

  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      // Check to see which players have mines in the sector
      if (plr_index <> sys_long_Player_ID) then
        set plr_id := plr_list.get(plr_index)
        // If we do not share mine codes, then add the number of mines to the sector count
        if (not Do_We_Have_Treaty_Element_With_Player(plr_id, TREATY_ELEMENT_TYPE_SHARE_CODES_FOR_MINEFIELDS, TRUE, 3)) then
          set mine_count := mine_count + Sys_Get_Number_Of_Units_In_Space_Sector(plr_id, "Mine", sys_loc, sect_loc)
          // Add up all the dangerous mines for a specific player
          set mine_count_enemy := mine_count + lst_AI_Enemy_Marked_Minefield_Count.get(plr_id)
          call lst_AI_Enemy_Marked_Minefield_Count.set(plr_id, mine_count_enemy)
        endif
      endif
    endfor
  endif

  return mine_count
end

//------------------------------------------------------------------------
// Get_Mine_Group_Owner
//------------------------------------------------------------------------
function Get_Mine_Group_Owner returns long
params
  sys_loc:                   long
  sect_loc:                  long
vars
  plr_list:                  longlist
  plr_count:                 long
  plr_index:                 long
  plr_id:                    long
  mine_count:                long
  mine_owner:                long
begin

  // Get all the players in this system
  call Sys_Get_Players_In_System_List(plr_list, sys_loc)

  // Identify the player owning a mine group in the defined sector
  set plr_count := plr_list.count()

  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      // Check to see which players have mines in the sector
      if (plr_index <> sys_long_Player_ID) then
        set plr_id := plr_list.get(plr_index)
        // If we do not share mine codes, then add the number of mines to the sector count
        set mine_count := Sys_Get_Number_Of_Units_In_Space_Sector(plr_id, "Mine", sys_loc, sect_loc)
        if (mine_count > 0) then
          set mine_owner := plr_id
        endif
      endif
    endfor
  endif

  return mine_owner
end

//------------------------------------------------------------------------
// Does_Sector_Have_Space_Object_Type
//------------------------------------------------------------------------
function Does_Sector_Have_Space_Object_Type returns boolean
params
  check_sys:                 long
  check_sect:                long
  sobj_type:                 long
vars
  sobj_list:                 longlist
  sector_occupied:           boolean := FALSE
begin

  if (Sys_Get_List_Of_Visible_Space_Objects_In_Sector(sys_long_Player_ID, sobj_type, check_sys, check_sect, sobj_list) > 0) then
    set sector_occupied := TRUE
  endif

  return sector_occupied
end

//------------------------------------------------------------------------
// Is_Player_Enemy
//------------------------------------------------------------------------
function Is_Player_Enemy returns boolean
params
  plr_1:                     long
  plr_2:                     long
  skip_known:                boolean
vars
  pol_status:                long
  is_enemy:                  boolean := FALSE
begin

  // Get our current political status with the target player
  set pol_status := Sys_Empire_Politics_Get_Status_With_Player(plr_1, plr_2)

  // If at war, then the player is an enemy
  if (pol_status = POLITICAL_STATUS_TYPE_WAR) then
    set is_enemy := TRUE
  endif

  // If the player is known, potentially consider the player an enemy
  if (pol_status = POLITICAL_STATUS_TYPE_KNOWN) and (not skip_known) then
    set is_enemy := TRUE
  endif

  return is_enemy
end

//------------------------------------------------------------------------
// Are_Others_Present_In_System
//------------------------------------------------------------------------
function Are_Others_Present_In_System returns boolean
params
  sys_loc:                   long
vars
  plr_list:                  longlist
  plr_count:                 long
  plr_index:                 long
  plr_id:                    long
  are_others_present:        boolean := FALSE
begin

  // Get all the players in this system
  call Sys_Get_Players_In_System_List(plr_list, sys_loc)
  set plr_count := plr_list.count()

  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      set plr_id := plr_list.get(plr_index)
      if (plr_id <> sys_long_Player_ID) then
        set are_others_present := TRUE
      endif
    endfor
  endif

  return are_others_present
end

//------------------------------------------------------------------------
// Does_Enemy_Have_Colony_In_System
//------------------------------------------------------------------------
function Does_Enemy_Have_Colony_In_System returns boolean
params
  sys_loc:                   long
vars
  plr_list:                  longlist
  plr_count:                 long
  plr_index:                 long
  plr_id:                    long
  planet_list:               longlist
  is_enemy_present:          boolean := FALSE
begin

  // Get all the players in this system
  call Sys_Get_Players_In_System_List(plr_list, sys_loc)

  // Do our enemies have a colony in this system?
  set plr_count := plr_list.count()

  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      set plr_id := plr_list.get(plr_index)
      if Sys_Empire_Politics_Is_Player_Enemy(sys_long_Player_ID, plr_id) and (plr_id <> sys_long_Player_ID) then
        if Sys_Player_Has_Colony_In_System(plr_id, sys_loc) then
          set is_enemy_present := TRUE
        endif
      endif
    endfor
  endif

  return is_enemy_present
end

//------------------------------------------------------------------------
// Is_Enemy_Present_In_System
//------------------------------------------------------------------------
function Is_Enemy_Present_In_System returns boolean
params
  sys_loc:                   long
vars
  plr_list:                  longlist
  plr_count:                 long
  plr_index:                 long
  plr_id:                    long
  is_enemy_present:          boolean := FALSE
begin

  // Get all the players in this system
  call Sys_Get_Players_In_System_List(plr_list, sys_loc)
  set plr_count := plr_list.count()

  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      set plr_id := plr_list.get(plr_index)
      if Sys_Empire_Politics_Is_Player_Enemy(sys_long_Player_ID, plr_id) and (plr_id <> sys_long_Player_ID) then
        set is_enemy_present := TRUE
      endif
    endfor
  endif

  return is_enemy_present
end

//------------------------------------------------------------------------
// Is_Enemy_Present_In_Adjacent_Systems
//------------------------------------------------------------------------
function Is_Enemy_Present_In_Adjacent_Systems returns boolean
params
  sys_loc:                   long
vars
  wp_count:                  long
  wp_index:                  long
  dest_sys:                  long
  is_enemy_present:          boolean := FALSE
begin

  // Get all the warp points
  set wp_count := Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, sys_loc)

  // Check for enemies in adjacent systems
  if (wp_count > 0) then
    loop
      set wp_index := wp_index + 1
      set dest_sys := Sys_Get_Solar_System_Warp_Point_Dest_System(sys_long_Player_ID, sys_loc, wp_index)
      set is_enemy_present := Is_Enemy_Present_In_System(dest_sys)
      exitwhen (wp_index >= wp_count) or (is_enemy_present)
    endloop
  endif

  return is_enemy_present
end

//------------------------------------------------------------------------
// Is_Enemy_Present_In_Sector
//------------------------------------------------------------------------
function Is_Enemy_Present_In_Sector returns boolean
params
  sys_loc:                   long
  sect_loc:                  long
vars
  plr_list:                  longlist
  plr_count:                 long
  plr_index:                 long
  plr_id:                    long
  is_enemy_present:          boolean := FALSE
begin

  // Get all the players in this sector
  call Sys_Get_Players_In_Sector_List(plr_list, sys_loc, sect_loc)

  // Are our enemies present in this system?
  set plr_count := plr_list.count()
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      set plr_id := plr_list.get(plr_index)
      if Sys_Empire_Politics_Is_Player_Enemy(sys_long_Player_ID, plr_id) and (plr_id <> sys_long_Player_ID) then
        set is_enemy_present := TRUE
      endif
    endfor
  endif

  return is_enemy_present
end

//------------------------------------------------------------------------
// Get_Destination_WP_Sector
//------------------------------------------------------------------------
function Get_Destination_WP_Sector returns long
params
  sys_loc:                   long
  dest_sys_loc:              long
vars
  wp_count:                  long
  wp_index:                  long
  dest_sys:                  long
  dest_sect:                 long
begin

  // Determine the corresponding warp point in the destination system
  set wp_count := Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, dest_sys_loc)
  if (wp_count > 0) then
    for wp_index := 1 to wp_count do
      set dest_sys := Sys_Get_Solar_System_Warp_Point_Dest_System(sys_long_Player_ID, dest_sys_loc, wp_index)
      // Check if our enemies are present in the destination warp point sector
      if (dest_sys = sys_loc) then
        set dest_sect := Sys_Get_Solar_System_Warp_Point_Sector(sys_long_Player_ID, dest_sys_loc, wp_index)
      endif
    endfor
  endif

  return dest_sect
end

//------------------------------------------------------------------------
// Is_Enemy_Present_At_Destination_WP
//------------------------------------------------------------------------
function Is_Enemy_Present_At_Destination_WP returns boolean
params
  sys_loc:                   long
  dest_sys_loc:              long
vars
  dest_sect:                 long
  is_enemy_present:          boolean := FALSE
begin

  // Determine the corresponding warp point in the destination system
  set dest_sect := Get_Destination_WP_Sector(sys_loc, dest_sys_loc)

  if (dest_sect > 0) then
    set is_enemy_present := Is_Enemy_Present_In_Sector(dest_sys_loc, dest_sect)
  endif

  return is_enemy_present
end

//------------------------------------------------------------------------
// Can_System_Be_Colonized
//------------------------------------------------------------------------
function Can_System_Be_Colonized returns boolean
params
  sys_loc:                   long
vars
  plr_count:                 long
  plr_index:                 long := 0
  planet_list:               longlist
  lst_treaty_elements:       longlist
  lst_treaty_clauses:        longlist
  element_count:             long := 0
  element_index:             long := 0
  element_id:                long
  ally_has_colony:           long := TRUE
  system_colonizable:        boolean := TRUE
begin

  // Get the number of players
  set plr_count := Sys_Get_Number_Of_Players()

  // Check to see if our treaty partners have a non-aggression clause
  if (plr_count > 0) then
    for plr_index := 1 to plr_count do
      if (plr_index <> sys_long_Player_ID) then
        if Sys_Player_Has_Colony_In_System(plr_index, sys_loc) then
          call Sys_Get_Treaty_Elements_Between_Empires(sys_long_Player_ID, plr_index, lst_treaty_elements, lst_treaty_clauses)
          // If we have a non-aggression element, we can't colonize the system
          set element_count := lst_treaty_elements.count()
          if (element_count > 0) then
            set element_index := lst_treaty_elements.indexof(TREATY_ELEMENT_TYPE_NON_AGGRESSION)
            // Check to see if can colonize each other's systems
            if (element_index > 0) then
              if (lst_treaty_clauses.get(element_index) <> 3) then
                set system_colonizable := FALSE
              endif
            endif
          endif
        endif
      endif
    endfor
  endif

  return system_colonizable
end

//------------------------------------------------------------------------
// Get_A_Colony_Location_In_System
//------------------------------------------------------------------------
function Get_A_Colony_Location_In_System returns long
params
  sys_loc:                   long
vars
  list_count:                long
  list_index:                long := 0
  planet_id:                 long
  planet_sys_loc:            long
  planet_sect_loc:           long := 0
begin

  // Get a colony's location in a system
  set list_count := lst_AI_Our_Colonies.count()
  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      set planet_id := lst_AI_Our_Colonies.get(list_index)
      set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)

      if (planet_sys_loc = sys_loc) then
        set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
      endif

      exitwhen (planet_sect_loc > 0) or (list_index >= list_count)
    endloop
  endif

  return planet_sect_loc
end

//------------------------------------------------------------------------
// Do_We_Have_Colonies_In_Adjacent_Systems
//------------------------------------------------------------------------
function Do_We_Have_Colonies_In_Adjacent_Systems returns boolean
params
  sys_loc:                   long
vars
  wp_count:                  long
  wp_index:                  long
  wp_dest_sys:               long
  have_colony:               boolean := FALSE
begin

  // Get a list of the warp points in this system
  set wp_count := Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, sys_loc)

  // Do we have colonies in the adjacent systems?
  if (wp_count > 0) then
    for wp_index := 1 to wp_count do
      set wp_dest_sys := Sys_Get_Solar_System_Warp_Point_Dest_System(sys_long_Player_ID, sys_loc, wp_index)
      // Check the warp point's destination
      if Sys_Player_Has_Colony_In_System(sys_long_Player_ID, wp_dest_sys) then
        set have_colony := TRUE
      endif
    endfor
  endif

  return have_colony
end

//------------------------------------------------------------------------
// Do_We_Have_Colonies_In_All_Connected_Systems
//------------------------------------------------------------------------
function Do_We_Have_Colonies_In_All_Connected_Systems returns boolean
params
  sys_loc:                   long
vars
  wp_count:                  long
  wp_index:                  long
  wp_dest_sys:               long
  have_colony:               boolean := TRUE
begin

  // Get a list of the warp points in this system
  set wp_count := Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, sys_loc)

  // Do we have colonies in the connected systems?
  if (wp_count > 0) then
    for wp_index := 1 to wp_count do
      set wp_dest_sys := Sys_Get_Solar_System_Warp_Point_Dest_System(sys_long_Player_ID, sys_loc, wp_index)
      // Check the warp point's destination
      if (not Sys_Player_Has_Colony_In_System(sys_long_Player_ID, wp_dest_sys)) then
        // Is it a dead end system we shouldn't worry about?
        if (not Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, wp_dest_sys) = 1) then
          set have_colony := FALSE
        endif
      endif
    endfor
  endif

  return have_colony
end

//------------------------------------------------------------------------
// Get_Colony_In_Location
//------------------------------------------------------------------------
function Get_Colony_In_Location returns long
params
  sobj_sys_loc:              long
  sobj_sect_loc:             long
vars
  list_count:                long
  list_index:                long
  lst_AI_colonies:           longlist
  planet_id:                 long
  planet_sys_loc:            long
  planet_sect_loc:           long
  found_planet_id:           long
begin

  // Determine if we have a colony in the space object's sector?
  set list_count := Sys_Get_List_Of_Players_Colonies(sys_long_Player_ID, lst_AI_colonies)

  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      set planet_id := lst_AI_Colonies.get(list_index)
      set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
      set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
      // Do we have a colony in the sector?
      if (planet_sys_loc = sobj_sys_loc) and (planet_sect_loc = sobj_sect_loc) then
        set found_planet_id := planet_id
      endif
      exitwhen (found_planet_id > 0) or (list_index >= list_count)
    endloop
  endif

  return found_planet_id
end

//------------------------------------------------------------------------
// Get_Distance_To_Nearest_Colony
//------------------------------------------------------------------------
function Get_Distance_To_Nearest_Colony returns long
params
  sobj_sys_loc:              long
  sobj_sect_loc:             long
vars
  list_count:                long
  list_index:                long
  lst_AI_colonies:           longlist
  min_dist:                  long := 999999
  this_dist:                 long
  planet_id:                 long
  planet_sys_loc:            long
  planet_sect_loc:           long
  dist_to_colony:            long
begin

  // Determine the nearest colony to our object's location
  set list_count := Sys_Get_List_Of_Players_Colonies(sys_long_Player_ID, lst_AI_colonies)

  if (list_count > 0) then
    for list_index := 1 to list_count do
      set planet_id := lst_AI_Colonies.get(list_index)
      set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)
      set planet_sect_loc := Sys_Get_Space_Object_Sector_Location(planet_id)
      set this_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, sobj_sys_loc, sobj_sect_loc, planet_sys_loc, planet_sect_loc)

      if (this_dist < min_dist) then
        set min_dist := this_dist
        set dist_to_colony := min_dist
      endif
    endfor
  endif

  return dist_to_colony
end

//------------------------------------------------------------------------
// Do_We_Have_A_Colony_Within_Distance
//------------------------------------------------------------------------
function Do_We_Have_A_Colony_Within_Distance returns boolean
params
  sobj_sys_loc:              long
  sobj_sect_loc:             long
  dist_to_check:             long
vars
  list_count:                long
  list_index:                long
  lst_AI_colonies:           longlist
  colony_id:                 long
  colony_sys_loc:            long
  colony_sect_loc:           long
  colony_dist:               long
  colony_present:            boolean := FALSE
begin

  // Determine the nearest colony to our object's location
  set list_count := Sys_Get_List_Of_Players_Colonies(sys_long_Player_ID, lst_AI_colonies)

  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      // Get our colony's location and distance
      set colony_id := lst_AI_Colonies.get(list_index)
      set colony_sys_loc := Sys_Get_Space_Object_System_Location(colony_id)
      set colony_sect_loc := Sys_Get_Space_Object_Sector_Location(colony_id)
      set colony_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, sobj_sys_loc, sobj_sect_loc, colony_sys_loc, colony_sect_loc)
      // Is our colony in the specified distance?
      if (colony_dist <= dist_to_check) then
        set colony_present := TRUE
      endif
      exitwhen (list_index >= list_count) or (colony_present)
    endloop
  endif

  return colony_present
end

//------------------------------------------------------------------------
// Are_Systems_Connected
//------------------------------------------------------------------------
function Are_Systems_Connected returns boolean
params
  orig_sys_loc:              long
  dest_sys_loc:              long
vars
  wp_count:                  long
  wp_index:                  long
  wp_dest_sys:               long
  systems_connected:         boolean := FALSE
begin

  // Get a list of the warp points in the originating system
  set wp_count := Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, orig_sys_loc)

  // Are the systems connected?
  if (wp_count > 0) then
    for wp_index := 1 to wp_count do
      set wp_dest_sys := Sys_Get_Solar_System_Warp_Point_Dest_System(sys_long_Player_ID, orig_sys_loc, wp_index)

      if (wp_dest_sys = dest_sys_loc) then
        set systems_connected := TRUE
      endif
    endfor
  endif

  return systems_connected
end

//------------------------------------------------------------------------
// Find_Nearest_System_By_Lightyears
//------------------------------------------------------------------------
function Find_Nearest_System_By_Lightyears returns long
params
  sys_loc:                   long
  max_wp_dist:               long
  check_for_colony:          boolean
  check_for_max_wp:          boolean
  check_for_connectivity:    boolean
  skip_connected:            boolean
  skip_protected:            boolean
  skip_enemy_systems:        boolean
vars
  sys_count:                 long
  sys_index:                 long
  max_num_wp:                long
  min_dist:                  long := 999999
  this_dist:                 long
  max_wp_count:              long
  dest_sys_loc:              long
  skip_system:               boolean := FALSE
begin

  // Determine the light year distance to the nearest valid system
  set sys_count := Sys_Get_Number_Of_Solar_Systems()

  if (sys_count > 0) then
    for sys_index := 1 to sys_count do
      if (sys_loc <> sys_index) then
        set skip_system := FALSE
        set this_dist := Sys_Get_Lightyear_Distance_Between_Systems(sys_loc, sys_index)

        if (this_dist > max_wp_dist) then
          set skip_system := TRUE
        endif

        // Set the maximum number of warp points for the selected system
        if (Sys_Get_Empire_Home_System(sys_long_Player_ID) = sys_index) then
          set max_num_wp := 10
        else
          set max_num_wp := 5
        endif

        // Do we have a colony in the destination system?
        if (check_for_colony) and (not skip_system) then
          if (not Sys_Player_Has_Colony_In_System(sys_long_Player_ID, sys_index)) then
            set skip_system := TRUE
          endif
        endif

        // Do we have any connectivity to the destination system?
        if (check_for_connectivity) and (not skip_system) then
          if (Sys_Get_System_Distance_Between_Solar_Systems(sys_loc, sys_index) < 999) then
            set skip_system := TRUE
          endif
        endif

        // Does the destination system have a direct warp point connection?
        if (skip_connected) and (not skip_system) then
          if Are_Systems_Connected(sys_loc, sys_index) then
            set skip_system := TRUE
          endif
        endif

        // Is this system protected by a System Gravitational Shield Facility?
        if (skip_protected) and (not skip_system) then
          if Is_System_Protected(sys_index) then
            set skip_system := TRUE
          endif
        endif

        // Is this system an enemy system?
        if (skip_enemy_systems) and (not skip_system) then
          if Does_Enemy_Have_Colony_In_System(sys_index) then
            set skip_system := TRUE
          endif
        endif

        // Determine the nearest system
        if (not skip_system) then
          if (this_dist < min_dist) then
            set min_dist := this_dist
            set dest_sys_loc := sys_index
          endif
        endif
      endif
    endfor
  endif

  return dest_sys_loc
end

//------------------------------------------------------------------------
// Get_Systems_Per_Player
//------------------------------------------------------------------------
function Get_Systems_Per_Player returns long
params
vars
  num_sys:                   long
  num_plr:                   long
  sys_per_plr:               long
begin

  // Divide the number of systems by the number of players
  set num_sys := Sys_Get_Number_Of_Solar_Systems()
  set num_plr := Sys_Get_Number_Of_Players()

  if (num_plr > 0) then
    set sys_per_plr := Sys_Divide_Long(num_sys, num_plr)
  endif
  
  return sys_per_plr
end

//------------------------------------------------------------------------
// Compute_Player_Overlap
//------------------------------------------------------------------------
function Compute_Player_Overlap returns long
params
  trg_plr:                   long
vars
  sys_count:                 long
  sys_index:                 long
  share_count:               long
  colony_sys_count:          long
  share_pct:                 long
begin

  // How much overlap do we have with the target player?
  set sys_count := Sys_Get_Number_Of_Solar_Systems()
  // Go through all the systems and compare which ones are shared with the target player
  if (sys_count > 0) then
    for sys_index := 1 to sys_count do
      // Do we have a colony in this system?
      if Sys_Player_Has_Colony_In_System(sys_long_Player_ID, sys_index) then
        set colony_sys_count := colony_sys_count + 1
        // Does the target player have a colony?
        if Sys_Player_Has_Colony_In_System(trg_plr, sys_index) then
          set share_count := share_count + 1
        endif
      endif
    endfor
  endif

  // Calculate the shared number of systems
  if (colony_sys_count > 0) then
    set share_pct := Sys_Divide_Long(share_count * 100, colony_sys_count)
  endif

  return share_pct
end

//------------------------------------------------------------------------
// Compute Map Location
//------------------------------------------------------------------------
function Compute_Quadrant_Location returns long
params
vars
  our_home_sys:              long
  sys_count:                 long
  sys_index:                 long
  sys_dist:                  long
  total_sys_dist:            long
  avg_sys_dist:              long
  location_score:            long
begin

  // Note our home system
  set our_home_sys := Sys_Get_Empire_Home_System(sys_long_Player_ID)

  // Get the lightyear distance between our home system and all other systems
  set sys_count := Sys_Get_Number_Of_Solar_Systems()
  if (sys_count > 0) then
    for sys_index := 1 to sys_count do
      if (our_home_sys <> sys_index) then
        set sys_dist := Sys_Get_Lightyear_Distance_Between_Systems(our_home_sys, sys_index)
        set total_sys_dist := total_sys_dist + sys_dist
      endif
    endfor
  endif

  // Calculate the average distance to the other systems
  if (sys_dist > 0) then
    set avg_sys_dist := Sys_Divide_Long(total_sys_dist, sys_count - 1)
  endif

  return avg_sys_dist
end

//------------------------------------------------------------------------
// Compute_Average_Distance_To_Player
//------------------------------------------------------------------------
function Compute_Average_Distance_To_Player returns long
params
  trg_plr:                   long
vars
  lst_colony:                longlist
  colony_count:              long
  colony_index:              long
  colony_id:                 long
  colony_sys:                long
  colony_sys_dist:           long
  total_sys_dist:            long
  our_home_sys:              long
  avg_sys_dist:              long
begin

  // Note our home system
  set our_home_sys := Sys_Get_Empire_Home_System(sys_long_Player_ID)

  // What's the average distance from our home system to the target player's colonies?
  set colony_count := Sys_Get_List_Of_Players_Colonies(trg_plr, lst_colony)
  // Sum up the total system distance to each colony
  if (colony_count > 0) then
    for colony_index := 1 to colony_count do
      set colony_id := lst_colony.get(colony_index)
      // What's the colony's system?
      set colony_sys := Sys_Get_Space_Object_System_Location(colony_id)
      // What's the systems distance to this colony from our home system?
      set colony_sys_dist := Sys_Get_System_Distance_Between_Solar_Systems(our_home_sys, colony_sys)
      set total_sys_dist := total_sys_dist + colony_sys_dist
    endfor
  endif

  // Calculate the average
  if (colony_count > 0) then
    set avg_sys_dist := Sys_Divide_Long(total_sys_dist, colony_count)
  endif

  return avg_sys_dist
end

//------------------------------------------------------------------------
// Find_Nearest_Object_In_List
//------------------------------------------------------------------------
function Find_Nearest_Object_In_List returns long
params
  sobj_list:                 longlist
  our_sys_loc:               long
  our_sect_loc:              long
  check_for_enemy:           boolean
  curr_system_only:          boolean
vars
  sobj_count:                long
  sobj_id:                   long
  sobj_index:                long
  sobj_sys_loc:              long
  sobj_sect_loc:             long
  sobj_dist:                 long
  min_dist:                  long := 999999
  skip_location:             boolean := FALSE
  nearest_sobj:              long := 0
begin

  // Cycle through a list ob objects and find the nearest object to our vehicle's position
  set sobj_count := sobj_list.count()

  if (sobj_count > 0) then
    for sobj_index := 1 to sobj_count do
      set sobj_id := sobj_list.get(sobj_index)
      set sobj_sys_loc := Sys_Get_Space_Object_System_Location(sobj_id)
      set sobj_sect_loc := Sys_Get_Space_Object_Sector_Location(sobj_id)
      set sobj_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, sobj_sys_loc, sobj_sect_loc, our_sys_loc, our_sect_loc)
      // Check for enemies
      if (check_for_enemy) then
        set skip_location := Is_Enemy_Present_In_Sector(sobj_sys_loc, sobj_sect_loc)
      endif
      // Restrict destination to current system if specified
      if (curr_system_only) then
        if (sobj_sys_loc = our_sys_loc) then
          set skip_location := FALSE
        else
          set skip_location := TRUE
        endif
      endif
      // Is this object closer than the previously closer object?
      if (sobj_dist < min_dist) and (not skip_location) then
        set nearest_sobj := sobj_id
        set min_dist := sobj_dist
      endif
    endfor
  endif

  return nearest_sobj
end

//------------------------------------------------------------------------
// Find_Nearest_Destination_In_List
//------------------------------------------------------------------------
function Find_Nearest_Destination_In_List returns long
params
  sobj_id:                   long
  dest_sys_loc_list:         longlist
  dest_sect_loc_list:        longlist
vars
  sobj_sys_loc:              long
  sobj_sect_loc:             long
  dest_count:                long
  dest_index:                long
  dest_sys_loc:              long
  dest_sect_loc:             long
  this_dist:                 long
  min_dist:                  long := 999999
  dest_sys_index:            long := 1
begin

  // Our vehicle's details
  set sobj_sys_loc := Sys_Get_Space_Object_System_Location(sobj_id)
  set sobj_sect_loc := Sys_Get_Space_Object_Sector_Location(sobj_id)

  // Check through the destination system list and find the closest one
  set dest_count := dest_sys_loc_list.count()

  if (dest_count > 0) then
    for dest_index := 1 to dest_count do
      // Get the destination location
      set dest_sys_loc := dest_sys_loc_list.get(dest_index)
      set dest_sect_loc := dest_sect_loc_list.get(dest_index)
      set this_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, sobj_sys_loc, sobj_sect_loc, dest_sys_loc, dest_sect_loc)
      // Is this object closer than the previously closer destination?
      if (this_dist < min_dist) then
        set min_dist := this_dist
        set dest_sys_index := dest_index
      endif
    endfor
  endif

  return dest_sys_index
end

//------------------------------------------------------------------------
// Find_Nearest_System_In_List
//------------------------------------------------------------------------
function Find_Nearest_System_In_List returns long
params
  sobj_id:                   long
  dest_sys_list:             longlist
vars
  sobj_sys:                  long
  dest_count:                long
  dest_index:                long
  dest_sys:                  long
  this_dist:                 long
  min_dist:                  long := 999999
  dest_sys_index:            long := 1
begin

  // Our vehicle's details
  set sobj_sys := Sys_Get_Space_Object_System_Location(sobj_id)

  // Check through the destination system list and find the closest one
  set dest_count := dest_sys_list.count()

  if (dest_count > 0) then
    for dest_index := 1 to dest_count do
      // Get the destination system
      set dest_sys := dest_sys_list.get(dest_index)
      set this_dist := Sys_Get_System_Distance_Between_Solar_Systems(sobj_sys, dest_sys)
      // Is this object closer than the previously closer system?
      if (this_dist < min_dist) then
        set min_dist := this_dist
        set dest_sys_index := dest_index
      endif
    endfor
  endif

  return dest_sys_index
end

//------------------------------------------------------------------------
// Is_Another_Ship_At_Location
//------------------------------------------------------------------------
function Is_Another_Ship_At_Location returns boolean
params
  target_ship_id:            long
  target_sys_loc:            long
  target_sect_loc:           long
  check_design_type:         boolean
  ai_design_type:            string
vars
  list_count:                long
  list_index:                long
  ship_id:                   long
  ship_design_type:          string
  ship_sys_loc:              long
  ship_sect_loc:             long
  check_location:            boolean
  ship_at_location:          boolean := FALSE
begin

  // Go through our list of ships
  set list_count := lst_AI_Our_Ships.count()

  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      // Get our ship's details
      set ship_id := lst_AI_Our_Ships.get(list_index)
      set ship_design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
      set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
      set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)

      if (ship_id <> target_ship_id) then
        // Check the ship's design type if required
        if (check_design_type) then
          if (ai_design_type = ship_design_type) then
            set check_location := TRUE
          else
            set check_location := FALSE
          endif
        endif
        // Is the location already occupied by a ship of this type?
        if (check_location) then
          if (target_sys_loc = ship_sys_loc) and (target_sect_loc = ship_sect_loc) then
            set ship_at_location := TRUE
          endif
        endif
      endif
      exitwhen (list_index >= list_count) or (ship_at_location)
    endloop
  endif

  return ship_at_location
end

//------------------------------------------------------------------------
// Does_Another_Ship_Have_Same_Order
//------------------------------------------------------------------------
function Does_Another_Ship_Have_Same_Order returns boolean
params
  target_ship_id:            long
  order_type:                long
  check_location:            boolean
  target_sys_loc:            long
  target_sect_loc:           long
  check_target:              boolean
  target_obj_id:             long
  check_design_type:         boolean
  ai_design_type:            string
vars
  list_count:                long
  list_index:                long
  ship_id:                   long
  ship_design_type:          string
  ship_order_type:           long
  ship_order_sys_loc:        long
  ship_order_sect_loc:       long
  ship_order_obj_id:         long
  check_orders:              boolean := TRUE
  order_issued:              boolean := FALSE
begin

  // Cycle through a list ob objects and find the nearest object to our vehicle's position
  set list_count := lst_AI_Our_Ships.count()

  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      // Get our ship's details
      set ship_id := lst_AI_Our_Ships.get(list_index)
      set ship_design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
      // Pending
      if (ship_id <> target_ship_id) then
        // Check the ship's design type if desired
        if (check_design_type) then
          if (ai_design_type = ship_design_type) then
            set check_orders := TRUE
          else
            set check_orders := FALSE
          endif
        endif
        // Check our ship's orders against the potential orders
        if (check_orders) then
          if (Sys_Get_Space_Object_Order_Count(ship_id) > 0) then
            // Get our ship's order details
            set ship_order_type := Sys_Get_Space_Object_Order_Type(ship_id, 1)
            set ship_order_sys_loc := Sys_Get_Space_Object_Order_System_Location(ship_id, 1)
            set ship_order_sect_loc := Sys_Get_Space_Object_Order_Sector_Location(ship_id, 1)
            set ship_order_obj_id := Sys_Get_Space_Object_Order_Target_Space_Object_ID(ship_id, 1)
            // Check our ship's order type
            if (ship_order_type = order_type) then
              set order_issued := TRUE
              // check our ship's order location
              if (check_location) then
                if (ship_order_sys_loc = target_sys_loc) and (ship_order_sect_loc = target_sect_loc) then
                  set order_issued := TRUE
                  // Check our ship's order target
                  if (check_target) then
                    if (ship_order_obj_id = target_obj_id) then
                      set order_issued := TRUE
                    else
                      set order_issued := FALSE
                    endif
                  endif
                else
                  set order_issued := FALSE
                endif
              endif
            else
              set order_issued := FALSE
            endif
          endif
        endif
      endif
      exitwhen (list_index >= list_count) or (order_issued)
    endloop
  endif

  return order_issued
end

//------------------------------------------------------------------------
// Find_Nearest_Ship_Distance_To_Location
//------------------------------------------------------------------------
function Find_Nearest_Ship_Distance_To_Location returns long
params
  target_sys_loc:            long
  target_sect_loc:           long
  check_design_type:         boolean
  ai_design_type:            string
  check_orders:              boolean
vars
  list_count:                long
  list_index:                long
  ship_id:                   long
  ship_design_type:          string
  ship_sys_loc:              long
  ship_sect_loc:             long
  ship_dist:                 long
  min_dist:                  long := 999999
  check_distance:            boolean := TRUE
begin

  // Cycle through a list ob objects and find the nearest object to our vehicle's position
  set list_count := lst_AI_Our_Ships.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      // Get our ship's details
      set ship_id := lst_AI_Our_Ships.get(list_index)
      set ship_design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
      // Check the ship's design type if desired
      if (check_design_type) then
        if (ai_design_type <> ship_design_type) then
          set check_distance := FALSE
        endif
      endif
      // Check the ship's order count if desired
      if (check_orders) then
        if (Sys_Get_Space_Object_Order_Count(ship_id) > 0) then
          set check_distance := FALSE
        endif
      endif
      // Determine the distance of the nearest valid ship
      if (check_distance) then
        set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
        set ship_sect_loc := Sys_Get_Space_Object_Sector_Location(ship_id)
        set ship_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, ship_sys_loc, ship_sect_loc, target_sys_loc, target_sect_loc)
        // Is this ship closer than the previously closer ship?
        if (ship_dist < min_dist) then
          set min_dist := ship_dist
        endif
      endif
    endfor
  endif

  return min_dist
end

//------------------------------------------------------------------------
// Find_Nearest_Ship_System_Distance_To_Location
//------------------------------------------------------------------------
function Find_Nearest_Ship_System_Distance_To_Location returns long
params
  target_sys_loc:            long
  check_design_type:         boolean
  ai_design_type:            string
  check_orders:              boolean
vars
  list_count:                long
  list_index:                long
  ship_id:                   long
  ship_design_type:          string
  ship_sys_loc:              long
  ship_dist:                 long
  min_dist:                  long := 999999
  check_distance:            boolean := TRUE
begin

  // Cycle through a list of objects and find the nearest object to our vehicle's position
  set list_count := lst_AI_Our_Ships.count()

  if (list_count > 0) then
    for list_index := 1 to list_count do
      // Get our ship's details
      set ship_id := lst_AI_Our_Ships.get(list_index)
      set ship_design_type := Sys_Get_Space_Object_AI_Design_Type(ship_id)
      // Check the ship's design type if desired
      if (check_design_type) then
        if (ai_design_type <> ship_design_type) then
          set check_distance := FALSE
        endif
      endif
      // Check the ship's order count if desired
      if (check_orders) then
        if (Sys_Get_Space_Object_Order_Count(ship_id) > 0) then
          set check_distance := FALSE
        endif
      endif
      // Determine the distance of the nearest valid ship
      if (check_distance) then
        set ship_sys_loc := Sys_Get_Space_Object_System_Location(ship_id)
        set ship_dist := Sys_Get_System_Distance_Between_Solar_Systems(ship_sys_loc, target_sys_loc)
        // Is this ship closer than the previously closer ship?
        if (ship_dist < min_dist) then
          set min_dist := ship_dist
        endif
      endif
    endfor
  endif

  return min_dist
end

//------------------------------------------------------------------------
// Find_Nearest_Space_Yard
//------------------------------------------------------------------------
function Find_Nearest_Space_Yard returns boolean
params
  sys_loc:                   long
  sect_loc:                  long
  target_sys_loc:            long byref
  target_sect_loc:           long byref
vars
  list_count:                long
  list_index:                long
  trg_id:                    long
  trg_sys_loc:               long
  trg_sect_loc:              long
  trg_dist:                  long
  min_dist:                  long := 999999
  space_yard_found:          boolean
begin

    // Find our nearest Space Yard for the given location
    set list_count := lst_AI_Our_Space_Yards.count()

    if (list_count > 0) then
      for list_index := 1 to list_count do
        set trg_id := lst_AI_Our_Space_Yards.get(list_index)
        set trg_sys_loc := Sys_Get_Space_Object_System_Location(trg_id)
        set trg_sect_loc := Sys_Get_Space_Object_Sector_Location(trg_id)
        set trg_dist := Sys_Get_Hex_Distance_Between_Sectors(sys_long_Player_ID, sys_loc, sect_loc, trg_sys_loc, trg_sect_loc)
        // Note the location of the nearest Space Yard
        if (trg_dist < min_dist) then
          set target_sys_loc := trg_sys_loc
          set target_sect_loc := trg_sect_loc
          set min_dist := trg_dist
        endif
      endfor
    endif

  if (target_sys_loc > 0) then
    set space_yard_found := TRUE
  else
    set space_yard_found := FALSE
  endif

  return space_yard_found
end

//------------------------------------------------------------------------
// Is_Colony_Type_In_System
//------------------------------------------------------------------------
function Is_Colony_Type_In_System returns boolean
params
  sys_loc:                   long
  colony_type:               string
vars
  list_count:                long
  list_index:                long := 0
  planet_id:                 long
  planet_sys_loc:            long
  colony_type_present:       boolean := FALSE
begin

  // Determine if we already have a colony of this type in the selected system
  set list_count := lst_AI_Our_Colonies.count()
  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      set planet_id := lst_AI_Our_Colonies.get(list_index)
      set planet_sys_loc := Sys_Get_Space_Object_System_Location(planet_id)

      if (planet_sys_loc = sys_loc) then
        if (Sys_Get_Planet_Colony_Type(planet_id) = colony_type) then
          set colony_type_present := TRUE
        endif
      endif

      exitwhen (colony_type_present) or (list_index >= list_count)
    endloop
  endif

  return colony_type_present
end

//------------------------------------------------------------------------
// Does_Enemy_Have_Colony_In_Adjacent_Systems
//------------------------------------------------------------------------
function Does_Enemy_Have_Colony_In_Adjacent_Systems returns boolean
params
  sys_loc:                   long
vars
  plr_list:                  longlist
  plr_count:                 long
  plr_index:                 long
  plr_id:                    long
  wp_count:                  long
  wp_index:                  long
  wp_dest_sys:               long
  is_enemy_present:          boolean := FALSE
begin

  // Get a list of the warp points in this system
  set wp_count := Sys_Get_Solar_System_Warp_Point_Count(sys_long_Player_ID, sys_loc)

  // Do our enemies have colonies in the adjacent systems?
  if (wp_count > 0) then
    for wp_index := 1 to wp_count do
      set wp_dest_sys := Sys_Get_Solar_System_Warp_Point_Dest_System(sys_long_Player_ID, sys_loc, wp_index)

      // Get all the players in this system
      call Sys_Get_Players_In_System_List(plr_list, wp_dest_sys)
      set plr_count := plr_list.count()

      if (plr_count > 0) then
        for plr_index := 1 to plr_count do
          set plr_id := plr_list.get(plr_index)

          if Sys_Empire_Politics_Is_Player_Enemy(sys_long_Player_ID, plr_id) and (plr_id <> sys_long_Player_ID) then
            if Sys_Player_Has_Colony_In_System(plr_id, wp_dest_sys) then
              set is_enemy_present := TRUE
            endif
         endif
        endfor
      endif
    endfor
  endif

  return is_enemy_present
end

//------------------------------------------------------------------------
// Does_System_Have_No_Planets
//------------------------------------------------------------------------
function Does_System_Have_No_Planets returns boolean
params
  sys_id:                    long
vars
  list_count:                long
  list_index:                long
  sobj_list:                 longlist
  sobj_id:                   long
  sobj_type:                 long
  system_has_no_planets:     boolean := TRUE
begin

  // Get Number of Players
  call Sys_Get_All_Visible_Space_Objects_In_System(sys_long_Player_ID, sys_id, sobj_list)
  set list_count := sobj_list.count()

  // Check the system for planets
  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      set sobj_id := sobj_list.get(list_index)
      set sobj_type := Sys_Get_Space_Object_Type(sobj_id)
      // Is this space object a planet?
      if (sobj_type = SPACE_OBJECT_TYPE_PLANET) then
        set system_has_no_planets := FALSE
      endif
      exitwhen (list_index >= list_count) or (not system_has_no_planets)
    endloop
  endif

  return system_has_no_planets
end

//------------------------------------------------------------------------
// Is_System_Nebula
//------------------------------------------------------------------------
function Is_System_Nebula returns boolean
params
  sys_id:                    long
vars
  lst_nebula_sys:            longlist
  sys_is_nebula:             boolean := FALSE
begin

  // Get a list of all the Nebulae
  call Sys_Get_List_Of_Nebulae(lst_nebula_sys)

  // Is the specified system a nebula?
  if (lst_nebula_sys.indexof(sys_id) > 0) then
    set sys_is_nebula := TRUE
  endif

  return sys_is_nebula
end

//------------------------------------------------------------------------
// Is_System_Blackhole
//------------------------------------------------------------------------
function Is_System_Blackhole returns boolean
params
  sys_id:                    long
vars
  lst_blackhole_sys:         longlist
  sys_is_blackhole:          boolean := FALSE
begin

  // Get a list of all the Black holes
  call Sys_Get_List_Of_Black_Holes(lst_blackhole_sys)

  // Does the specified system contain a black hole?
  if (lst_blackhole_sys.indexof(sys_id) > 0) then
    set sys_is_blackhole := TRUE
  endif

  return sys_is_blackhole
end

//------------------------------------------------------------------------
// Get_Planet_Atmosphere_Type_Name
//------------------------------------------------------------------------
function Get_Planet_Atmosphere_Type_Name returns string
params
  atmosphere_type:           long
vars
  atmosphere_type_name:      string
begin

  // Translate our atmosphere type to a name
  case atmosphere_type
    ATMOSPHERE_TYPE_NONE:
      set atmosphere_type_name := "None"
    ATMOSPHERE_TYPE_OXYGEN:
      set atmosphere_type_name := "Oxygen"
    ATMOSPHERE_TYPE_METHANE:
      set atmosphere_type_name := "Methane"
    ATMOSPHERE_TYPE_HYDROGEN:
      set atmosphere_type_name := "Hydrogen"
    ATMOSPHERE_TYPE_CARBON_DIOXIDE:
      set atmosphere_type_name := "Carbon Dioxide"
  endcase

  return atmosphere_type_name
end

//------------------------------------------------------------------------
// Get_Planet_Physical_Type_Name
//------------------------------------------------------------------------
function Get_Planet_Physical_Type_Name returns string
params
  planet_id:                 long
vars
  planet_type_name:          string
begin

  // Translate our planet physical type to a name
  case Sys_Get_Planet_Physical_Type(planet_id)
    PLANET_TYPE_ROCK:
      set planet_type_name := "Rock"
    PLANET_TYPE_ICE:
      set planet_type_name := "Ice"
    PLANET_TYPE_GAS_GIANT:
      set planet_type_name := "Gas Giant"
  endcase

  return planet_type_name
end

//------------------------------------------------------------------------
// Get_Colonization_Ability_Name
//------------------------------------------------------------------------
function Get_Colonization_Ability_Name returns string
params
  colonization_ability:      long
vars
  colonization_ability_name: string
begin

  // Determine our planet's atmosphere
  case colonization_ability
    COLONIZE_ROCK:
      set colonization_ability_name := "Rock"
    COLONIZE_ICE:
      set colonization_ability_name := "Ice"
    COLONIZE_GAS:
      set colonization_ability_name := "Gas"
    COLONIZE_ICE_AND_GAS:
      set colonization_ability_name := "Ice + Gas"
    COLONIZE_ROCK_AND_GAS:
      set colonization_ability_name := "Rock + Gas"
    COLONIZE_ROCK_AND_ICE:
      set colonization_ability_name := "Rock + Ice"
    COLONIZE_ALL:
      set colonization_ability_name := "All"
  endcase

  return colonization_ability_name
end

//------------------------------------------------------------------------
// Get_Planet_Size
//------------------------------------------------------------------------
function Get_Planet_Size returns long
params
  planet_id:                 long
vars
  planet_size:               long
begin

  // Determine our planet's atmosphere
  case Sys_Get_Planet_Size(planet_id)
    "Tiny":
      set planet_size := PLANET_SIZE_TINY
    "Small":
      set planet_size := PLANET_SIZE_SMALL
    "Medium":
      set planet_size := PLANET_SIZE_MEDIUM
    "Large":
      set planet_size := PLANET_SIZE_LARGE
    "Huge":
      set planet_size := PLANET_SIZE_HUGE
    "Ringworld":
      set planet_size := PLANET_SIZE_RINGWORLD
    "Sphereworld":
      set planet_size := PLANET_SIZE_SPHEREWORLD
  endcase

  return planet_size
end

//------------------------------------------------------------------------
// Get_Native_Atmosphere
//------------------------------------------------------------------------
function Get_Native_Atmosphere returns long
params
  plr_id:                    long
vars
  lst_planets:               longlist
  list_count:                long
  list_index:                long
  planet_id:                 long
  native_atmosphere:         long
begin

  // Get a list of all the planets
  set list_count := Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_PLANET, lst_planets, FALSE, TRUE, 0)

  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      set planet_id := lst_planets.get(list_index)
      // Is the planet breathable?
      if Sys_Is_Planet_Breathable(planet_id, plr_id) then
        set native_atmosphere := Sys_Get_Planet_Atmosphere_Type(planet_id)
      endif
      exitwhen (list_index >= list_count) or (native_atmosphere > 0)
    endloop
  endif

  return native_atmosphere
end

//------------------------------------------------------------------------
// Get_Colonization_Ability
//------------------------------------------------------------------------
function Get_Colonization_Ability returns long
params
  plr_id:                    long
vars
  tech_id:                   long
  has_rock:                  boolean := FALSE
  has_ice:                   boolean := FALSE
  has_gas:                   boolean := FALSE
  colonization_ability:      long
begin

  // Do we have Rock?
  set tech_id := Sys_Get_Tech_ID("Rock Planet Colonization")
  set has_rock := Sys_Is_Empire_Research_Tech_At_Maximum(plr_id, tech_id)
  // Do we have Ice?
  set tech_id := Sys_Get_Tech_ID("Ice Planet Colonization")
  set has_ice := Sys_Is_Empire_Research_Tech_At_Maximum(plr_id, tech_id)
  // Do we have Gas?
  set tech_id := Sys_Get_Tech_ID("Gas Giant Colonization")
  set has_gas := Sys_Is_Empire_Research_Tech_At_Maximum(plr_id, tech_id)

  // Note our colonization ability
  if (has_rock) and (has_ice) and (has_gas) then
    set colonization_ability := COLONIZE_ALL
  else
    if (has_ice) and (has_gas) then
      set colonization_ability := COLONIZE_ICE_AND_GAS
    else
      if (has_rock) and (has_gas) then
        set colonization_ability := COLONIZE_ROCK_AND_GAS
      else
        if (has_rock) and (has_ice) then
          set colonization_ability := COLONIZE_ROCK_AND_ICE
        else
          if (has_gas) then
            set colonization_ability := COLONIZE_GAS
          else
            if (has_ice) then
              set colonization_ability := COLONIZE_ICE
            else
              set colonization_ability := COLONIZE_ROCK
            endif
          endif
        endif
      endif
    endif
  endif

  return colonization_ability
end

//------------------------------------------------------------------------
// Check_For_Colonization_Game_Restrictions
//------------------------------------------------------------------------
function Check_For_Colonization_Game_Restrictions returns boolean
params
  plr_id:                    long
  breathable_only:           boolean
  home_type_only:            boolean
vars
  lst_planets:               longlist
  list_count:                long
  list_index:                long
  planet_id:                 long
  planet_type:               long
  atmosphere_type:           long
  tech_id:                   long
  has_rock:                  boolean := FALSE
  has_ice:                   boolean := FALSE
  has_gas:                   boolean := FALSE
  colonize_breathable_only:  boolean := TRUE
  colonize_home_type_only:   boolean := FALSE
begin

  // Note our colonization technologies
  // Do we have Rock?
  set tech_id := Sys_Get_Tech_ID("Rock Planet Colonization")
  set has_rock := Sys_Is_Empire_Research_Tech_At_Maximum(plr_id, tech_id)
  // Do we have Ice?
  set tech_id := Sys_Get_Tech_ID("Ice Planet Colonization")
  set has_ice := Sys_Is_Empire_Research_Tech_At_Maximum(plr_id, tech_id)
  // Do we have Gas?
  set tech_id := Sys_Get_Tech_ID("Gas Giant Colonization")
  set has_gas := Sys_Is_Empire_Research_Tech_At_Maximum(plr_id, tech_id)

  // Get a list of all the planets
  set list_count := Sys_Get_List_Of_Space_Objects_Of_Type(SPACE_OBJECT_TYPE_PLANET, lst_planets, FALSE, TRUE, 0)

  // Check through the planets
  if (list_count > 0) then
    loop
      set list_index := list_index + 1
      set planet_id := lst_planets.get(list_index)
      set planet_type := Sys_Get_Planet_Physical_Type(planet_id)
      // If the planet is not breathable...
      if (not Sys_Is_Planet_Breathable(planet_id, plr_id)) then
        // ...but we can colonize so there must be no restrictions on atmosphere
        if Sys_Can_Colonize_Planet(plr_id, planet_id) then
          set colonize_breathable_only := FALSE
        else
          // ...but if we can't colonize it but have the right colonization tech for the planet physical type then...
          if (has_rock and (planet_type = PLANET_TYPE_ROCK)) or (has_ice and (planet_type = PLANET_TYPE_ICE)) or (has_gas and (planet_type = PLANET_TYPE_GAS_GIANT)) then
            set colonize_home_type_only := TRUE
          endif
        endif
      endif
      exitwhen (list_index >= list_count) or (not colonize_breathable_only and breathable_only) or (colonize_home_type_only and home_type_only)
    endloop
  endif

  // Return the result
  if (breathable_only) then
    return colonize_breathable_only
  endif
  if (home_type_only) then
    return colonize_home_type_only
  endif

end

//------------------------------------------------------------------------
// Is_Planet_Breathable_By_Population
//------------------------------------------------------------------------
function Is_Planet_Breathable_By_Population returns boolean
params
  planet_id:                 long
vars
  planet_breathable:         boolean := TRUE
begin

  // Is the planet domed?
  if Sys_Is_Planet_Domed(planet_id) then
    set planet_breathable := FALSE
  endif

  return planet_breathable
end

//------------------------------------------------------------------------
// Get_Population_ID
//------------------------------------------------------------------------
function Get_Population_ID returns long
params
  planet_id:                 long
vars
  cargo_count:               long
  cargo_index:               long
  cargo_item_id:             long
  population_id:             long
begin

  // Get the items in our planet's cargo
  set cargo_count := Sys_Get_Space_Object_Cargo_Item_Count(planet_id)

  // Check to see if the population can breathe the planet's atmosphere
  if (cargo_count > 0) then
    loop
      set cargo_index := cargo_index + 1
      set cargo_item_id := Sys_Get_Space_Object_Cargo_Item_ID(planet_id, cargo_index)
      // Check planet for populations
      if (Sys_Get_Space_Object_Cargo_Item_Type(planet_id, cargo_item_id) = CARGO_ITEM_TYPE_POPULATION) then
        set population_id := cargo_item_id
      endif
      exitwhen (cargo_index >= cargo_count) or (population_id > 0)
    endloop
  endif

  return population_id
end

//------------------------------------------------------------------------
// Get_Planet_Population_Pct
//------------------------------------------------------------------------
function Get_Planet_Population_Pct returns long
params
  planet_id:                 long
vars
  planet_pop:                long
  planet_size:               string
  max_pop:                   long
  pop_pct:                   long
begin

  // Get our planet's details
  set planet_pop := Sys_Get_Planet_Population(planet_id)
  set planet_size := Sys_Get_Planet_Size(planet_id)

  // Get our planet's maximum population amount
  case planet_size
    "Tiny":
      set max_pop := 500
    "Small":
      set max_pop := 1000
    "Medium":
      set max_pop := 2500
    "Large":
      set max_pop := 5000
    "Huge":
      set max_pop := 10000
    "Ringworld":
      set max_pop := 25000
    "Sphereworld":
      set max_pop := 50000
  endcase

  // Adjust the maximum planet population if our planet is domed
  if Sys_Is_Planet_Domed(planet_id) then
    set max_pop := Sys_Divide_Long(max_pop, 5)
  endif

  // Get our planet's current population percentage
  set pop_pct := Sys_Trunc(100 * planet_pop / max_pop)

  return pop_pct
end

//------------------------------------------------------------------------
// Get_Planet_Population_Space_Available
//------------------------------------------------------------------------
function Get_Planet_Population_Space_Available returns long
params
  planet_id:                 long
vars
  planet_pop:                long
  planet_size:               string
  max_pop:                   long
  pop_space_available:       long
begin

  // Get our planet's details
  set planet_pop := Sys_Get_Planet_Population(planet_id)
  set planet_size := Sys_Get_Planet_Size(planet_id)

  // Get our planet's maximum population amount
  case planet_size
    "Tiny":
      set max_pop := 500
    "Small":
      set max_pop := 1000
    "Medium":
      set max_pop := 2500
    "Large":
      set max_pop := 5000
    "Huge":
      set max_pop := 10000
    "Ringworld":
      set max_pop := 25000
    "Sphereworld":
      set max_pop := 50000
  endcase

  // Adjust the maximum planet population if our planet is domed
  if Sys_Is_Planet_Domed(planet_id) then
    set max_pop := Sys_Divide_Long(max_pop, 5)
  endif

  // Substract the maximum from the current
  set pop_space_available := max_pop - planet_pop

  return pop_space_available
end

//------------------------------------------------------------------------
// Do_We_Need_More_Cargo
//------------------------------------------------------------------------
function Do_We_Need_More_Cargo returns boolean
params
  ship_id:                   long
  cargo_type:                long
  unit_type:                 string
  min_pct:                   long
vars
  space_total:               long
  space_used:                long
  space_pct:                 long
  more_cargo_needed:         boolean := FALSE
begin

  // Get the space used on the requested cargo item
  set space_total := Sys_Get_Space_Object_Cargo_Total_Space(ship_id)
  set space_used := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, cargo_type, unit_type)
  set space_pct := Sys_Trunc(100 * space_used / space_total)

  // Is the space used less then the minimum desired?
  if (space_pct < min_pct) then
    set more_cargo_needed := TRUE
  endif

  return more_cargo_needed
end

//------------------------------------------------------------------------
// What_Unit_Type_Is_Our_Main_Cargo
//------------------------------------------------------------------------
function What_Unit_Type_Is_Our_Main_Cargo returns string
params
  ship_id:                   long
vars
  index:                     long
  space_used:                long
  most_space_used:           long
  this_unit_type:            string
  unit_type:                 string
begin

  // Determine which unit in cargo we have the most of
  for index := 1 to 5 do
    case index
      1:
        set space_used := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, CARGO_ITEM_TYPE_UNIT, "Troop")
        set this_unit_type  := "Troop"
      2:
        set space_used := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, CARGO_ITEM_TYPE_UNIT, "Fighter")
        set this_unit_type  := "Fighter"
      3:
        set space_used := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, CARGO_ITEM_TYPE_UNIT, "Satellite")
        set this_unit_type  := "Satellite"
      4:
        set space_used := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, CARGO_ITEM_TYPE_UNIT, "Weapon Platform")
        set this_unit_type  := "Weapon Platform"
      5:
        set space_used := Sys_Get_Space_Object_Cargo_Space_Used_On_Type(ship_id, CARGO_ITEM_TYPE_UNIT, "Drone")
        set this_unit_type  := "Drone"
    endcase
    // Return the unit
    if (space_used > most_space_used) then
      set most_space_used := space_used
      set unit_type := this_unit_type
    endif
  endfor

  return unit_type
end

//------------------------------------------------------------------------
// Does_Colony_Need_More_Units
//------------------------------------------------------------------------
function Does_Colony_Need_More_Units returns boolean
params
  planet_id:                 long
  min_pct:                   long
vars
  space_total:               long
  space_used:                long
  space_pct:                 long
  more_units_needed:         boolean := FALSE
begin

  // Get the space used on the requested cargo item
  set space_total := Sys_Get_Space_Object_Cargo_Total_Space(planet_id)
  set space_used := Sys_Get_Space_Object_Cargo_Space_Remaining(planet_id)
  set space_pct := Sys_Trunc(100 * space_used / space_total)

  // Is the space used less then the minimum desired?
  if (space_pct < min_pct) then
    set more_units_needed := TRUE
  endif

  return more_units_needed
end

//------------------------------------------------------------------------
// Compute_Resource_Income
//------------------------------------------------------------------------
function Compute_Resource_Income returns resources
params
vars
  resources_income:          resources
begin

  // Determine our resource income
  call resources_income.add(Sys_Get_Player_Resources_Received_Per_Turn(sys_long_Player_ID))
  call resources_income.add(Sys_AI_Empire_Stats_Get_Total_Remote_Mined_Resources(sys_long_Player_ID))

  return resources_income
end

//------------------------------------------------------------------------
// Compute_Resources_Spent
//------------------------------------------------------------------------
function Compute_Resources_Spent returns resources
params
vars
  resources_spent:           resources
begin

  // Determine our spent resources
  call resources_spent.add(Sys_AI_Empire_Stats_Get_Total_Tariff_Resources_Expenses(sys_long_Player_ID))
  call resources_spent.add(Sys_AI_Empire_Stats_Get_Total_Maintenance_Resources_Expenses(sys_long_Player_ID))
  call resources_spent.add(Sys_AI_Empire_Stats_Get_Total_Construction_Resources_Expenses(sys_long_Player_ID))

  return resources_spent
end

//------------------------------------------------------------------------
// Compute_Resources_Stored
//------------------------------------------------------------------------
function Compute_Resources_Stored returns resources
params
vars
  resources_stored:          resources
begin

  // Determine our resources in storage
  call resources_stored.assign(Sys_AI_Empire_Stats_Get_Current_Resources(sys_long_Player_ID))

  return resources_stored
end

//------------------------------------------------------------------------
// Compute_Resource_Balances
//------------------------------------------------------------------------
function Compute_Resource_Balances returns boolean
params
vars
  resources_total:           resources
  resources_stored:          resources
  resources_spent:           resources
  spent_minerals:            real
  spent_organics:            real
  spent_radioactives:        real
  net_minerals:              real
  net_organics:              real
  net_radioactives:          real
  stored_minerals:           real
  stored_organics:           real
  stored_radioactives:       real
  min_minerals:              real
  min_organics:              real
  min_radioactives:          real
begin

  // Get our stored, received, and expense resources
  call resources_total.assign(Compute_Resource_Income())
  call resources_stored.assign(Compute_Resources_Stored())
  call resources_spent.assign(Compute_Resources_Spent())

  // Subtract our resource expenses
  set spent_minerals := resources_spent.get(RESOURCE_TYPE_MINERALS)
  set spent_organics := resources_spent.get(RESOURCE_TYPE_ORGANICS)
  set spent_radioactives := resources_spent.get(RESOURCE_TYPE_RADIOACTIVES)

  // Get our total specific resources
  set net_minerals := resources_total.get(RESOURCE_TYPE_MINERALS) - spent_minerals
  set net_organics := resources_total.get(RESOURCE_TYPE_ORGANICS) - spent_organics
  set net_radioactives := resources_total.get(RESOURCE_TYPE_RADIOACTIVES) - spent_radioactives

  // Get our stored resources
  set stored_minerals := resources_stored.get(RESOURCE_TYPE_MINERALS)
  set stored_organics := resources_stored.get(RESOURCE_TYPE_ORGANICS)
  set stored_radioactives := resources_stored.get(RESOURCE_TYPE_RADIOACTIVES)

  // Set our min and max resources to convert
  set min_minerals := Sys_Max_Real(5000.0, stored_minerals * 0.1)
  set min_organics := Sys_Max_Real(5000.0, stored_minerals * 0.1)
  set min_radioactives := Sys_Max_Real(5000.0, stored_minerals * 0.1)

  set lng_Max_Minerals_Needed := Sys_Trunc(real_Max_Minerals_Storage - stored_minerals)
  set lng_Max_Organics_Needed := Sys_Trunc(real_Max_Organics_Storage - stored_organics)
  set lng_Max_Radioactives_Needed := Sys_Trunc(real_Max_Radioactives_Storage - stored_radioactives)

  if (lng_Max_Minerals_Needed > lng_Max_Organics_Needed) and (lng_Max_Minerals_Needed > lng_Max_Radioactives_Needed) then
    set lng_Max_Organics_Needed := 0
    set lng_Max_Radioactives_Needed := 0
  endif
  if (lng_Max_Organics_Needed > lng_Max_Minerals_Needed) and (lng_Max_Organics_Needed > lng_Max_Radioactives_Needed) then
    set lng_Max_Minerals_Needed := 0
    set lng_Max_Radioactives_Needed := 0
  endif
  if (lng_Max_Radioactives_Needed > lng_Max_Minerals_Needed) and (lng_Max_Radioactives_Needed > lng_Max_Organics_Needed) then
    set lng_Max_Minerals_Needed := 0
    set lng_Max_Organics_Needed := 0
  endif

  // Update our global modifiers
  // Minerals
  if (net_minerals >= 0) then
    set lng_Minerals_Surplus := Sys_Trunc(net_minerals)
    // Is it a significant surplus?
    if (lng_Minerals_Surplus > min_minerals) then
      set bool_Race_Minerals_Surplus := TRUE
    endif
    // Set our maximum minerals to convert
    if (not bool_Race_Converted_Resources) and (not bool_Race_Minerals_Low) then
      set lng_Max_Minerals_To_Convert := Sys_Max_Long(5000, lng_Minerals_Surplus)
    endif
  else
    set lng_Minerals_Deficit := Sys_Trunc(-net_minerals)
    // Is it a significant deficit?
    if (lng_Minerals_Deficit > min_minerals) then
      set bool_Race_Minerals_Deficit := TRUE
    endif
  endif
  // Organics
  if (net_organics >= 0) then
    set lng_Organics_Surplus := Sys_Trunc(net_organics)
    // Is it a significant surplus?
    if (lng_Organics_Surplus > min_organics) then
      set bool_Race_Organics_Surplus := TRUE
    endif
    // Set our maximum organics to convert
    if (not bool_Race_Converted_Resources) and (not bool_Race_Organics_Low) then
      set lng_Max_Organics_To_Convert := Sys_Max_Long(5000, lng_Organics_Surplus)
    endif
  else
    set lng_Organics_Deficit := Sys_Trunc(-net_organics)
    // Is it a significant deficit?
    if (lng_Organics_Deficit > min_organics) then
      set bool_Race_Organics_Deficit := TRUE
    endif
  endif
  // Radioactives
  if (net_radioactives >= 0) then
    set lng_Radioactives_Surplus := Sys_Trunc(net_radioactives)
    // Is it a significant surplus?
    if (lng_Radioactives_Surplus > min_radioactives) and (not bool_Race_Radioactives_Low) then
      set bool_Race_Radioactives_Surplus := TRUE
    endif
    // Set our maximum radioactives to convert
    if (not bool_Race_Converted_Resources) then
      set lng_Max_Radioactives_To_Convert := Sys_Max_Long(5000, lng_Radioactives_Surplus)
    endif
  else
    set lng_Radioactives_Deficit := Sys_Trunc(-net_radioactives)
    // Is it a significant deficit?
    if (lng_Radioactives_Deficit > min_radioactives) then
      set bool_Race_Radioactives_Deficit := TRUE
    endif
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Compute_Resource_Levels
//------------------------------------------------------------------------
function Compute_Resource_Levels returns boolean
params
vars
  resources_maint:           resources
  maint_minerals:            real
  maint_organics:            real
  maint_radioactives:        real
  resources_stored:          resources
  stored_minerals:           real
  stored_organics:           real
  stored_radioactives:       real
  low_minerals:              real
  high_minerals:             real
  low_organics:              real
  high_organics:             real
  low_radioactives:          real
  high_radioactives:         real
begin

  // Get our resource amounts for maintenance and storage
  call resources_maint.assign(Sys_AI_Empire_Stats_Get_Total_Maintenance_Resources_Expenses(sys_long_Player_ID))
  call resources_stored.assign(Sys_AI_Empire_Stats_Get_Current_Resources(sys_long_Player_ID))

  // Note our specific maintenance resource usage
  set maint_minerals := resources_maint.get(RESOURCE_TYPE_MINERALS)
  set maint_organics := resources_maint.get(RESOURCE_TYPE_ORGANICS)
  set maint_radioactives := resources_maint.get(RESOURCE_TYPE_RADIOACTIVES)

  // Note our specific resource levels in storage
  set stored_minerals := resources_stored.get(RESOURCE_TYPE_MINERALS)
  set stored_organics := resources_stored.get(RESOURCE_TYPE_ORGANICS)
  set stored_radioactives := resources_stored.get(RESOURCE_TYPE_RADIOACTIVES)

  // Set our low and high storage amounts for resources
  set low_minerals := Sys_Max_Real(5000.0, maint_minerals * 0.5)
  set high_minerals := Sys_Max_Real(50000.0, maint_minerals * 2.0)
  set low_organics := Sys_Max_Real(3000.0, maint_organics * 0.5)
  set high_organics := Sys_Max_Real(20000.0, maint_organics * 2.0)
  set low_radioactives := Sys_Max_Real(3000.0, maint_radioactives * 0.5)
  set high_radioactives := Sys_Max_Real(20000.0, maint_radioactives * 2.0)

  // Update our global resource level modifiers

  // Minerals level
  if (stored_minerals < low_minerals) and (not bool_Race_Minerals_Surplus) then
    set bool_Race_Minerals_Low := TRUE
  endif
  if (stored_minerals >= high_minerals) or ((lng_Minerals_Surplus > maint_minerals * 0.5) and (stored_minerals > 50000)) then
    set bool_Race_Minerals_High := TRUE
  endif
  if (not bool_Race_Minerals_Low) and (not bool_Race_Minerals_High) then
    set bool_Race_Minerals_Adequate := TRUE
  endif
  // Do we need more minerals storage?
  if (stored_minerals > real_Max_Minerals_Storage * 0.8) and (real_Max_Minerals_Storage < maint_minerals * 2) then
    set bool_Race_Needs_Minerals_Storage := TRUE
  endif

  // Organics level
  if (stored_organics < low_organics) and (not bool_Race_Organics_Surplus) then
    set bool_Race_Organics_Low := TRUE
  endif
  if (stored_organics >= high_organics) or ((lng_Organics_Surplus > maint_organics * 0.5) and (stored_organics > 50000)) then
    set bool_Race_Organics_High := TRUE
  endif
  if (not bool_Race_Organics_Low) and (not bool_Race_Organics_High) then
    set bool_Race_Organics_Adequate := TRUE
  endif
  // Do we need more organics storage?
  if (stored_organics > real_Max_Organics_Storage * 0.8) and (real_Max_Organics_Storage < maint_organics * 2) then
    set bool_Race_Needs_Organics_Storage := TRUE
  endif

  // Radioactives level
  if (stored_radioactives < low_radioactives) and (not bool_Race_Radioactives_Surplus) then
    set bool_Race_Radioactives_Low := TRUE
  endif
  if (stored_radioactives >= high_radioactives) or ((lng_Radioactives_Surplus > maint_radioactives * 0.5) and (stored_radioactives > 50000)) then
    set bool_Race_Radioactives_High := TRUE
  endif
  if (not bool_Race_Radioactives_Low) and (not bool_Race_Radioactives_High) then
    set bool_Race_Radioactives_Adequate := TRUE
  endif
  // Do we need more radioactives storage?
  if (stored_radioactives > real_Max_Radioactives_Storage * 0.8) and (real_Max_Radioactives_Storage < maint_radioactives * 2) then
    set bool_Race_Needs_Radioactives_Storage := TRUE
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Estimate_Pending_Resource_Production
//------------------------------------------------------------------------
function Estimate_Pending_Resource_Production returns boolean
params
vars
  lst_queues:                longlist
  queue_count:               long
  queue_index:               long
  queue_id:                  long
  num_minerals:              long
  num_organics:              long
  num_radioactives:          long
  num_monolith:              long
  num_solar_generator:       long
begin

  // Go through our queues and count our resource facilities under construction
  set queue_count := Sys_Get_List_Of_Players_Construction_Queues(sys_long_Player_ID, lst_queues)

  if (queue_count > 0) then
    for queue_index := 1 to queue_count do
      set queue_id := lst_queues.get(queue_index)
      // Get the number of resource facilities under construction in this queue
      set num_minerals := num_minerals + Sys_Get_Construction_Queue_Specific_Facility_Count(queue_id, "Mineral Miner Facility")
      set num_organics := num_organics + Sys_Get_Construction_Queue_Specific_Facility_Count(queue_id, "Organics Farm Facility")
      set num_radioactives := num_radioactives + Sys_Get_Construction_Queue_Specific_Facility_Count(queue_id, "Radioactives Extraction Facility")
      set num_monolith := num_monolith + Sys_Get_Construction_Queue_Specific_Facility_Count(queue_id, "Monolith Facility")
      set num_solar_generator := num_solar_generator + Sys_Get_Construction_Queue_Specific_Facility_Count(queue_id, "Solar Generator")
    endfor
  endif

  // Estimate our upcoming resource production
  set real_Minerals_Prod_Pending := (num_minerals * 2000.0) + (num_monolith * 1500.0) + (num_solar_generator * 1000.0)
  set real_Organics_Prod_Pending := (num_organics * 2000.0) + (num_monolith * 1500.0) + (num_solar_generator * 1000.0)
  set real_Radioactives_Prod_Pending := (num_radioactives * 2000.0) + (num_monolith * 1500.0) + (num_solar_generator * 1000.0)

  return TRUE
end

//------------------------------------------------------------------------